Skip to content

Commit

Permalink
clear in-scope lifetimes for nested items in HIR lowering
Browse files Browse the repository at this point in the history
This was causing us to incorrectly think the lifetimes were
already declared on the scope for the nested item, when in fact
they are not inherited.
  • Loading branch information
nikomatsakis committed Aug 13, 2019
1 parent a02a171 commit e4756e6
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/librustc/hir/lowering/item.rs
Expand Up @@ -60,10 +60,12 @@ impl<'tcx, 'interner> Visitor<'tcx> for ItemLowerer<'tcx, 'interner> {
fn visit_item(&mut self, item: &'tcx Item) {
let mut item_hir_id = None;
self.lctx.with_hir_id_owner(item.id, |lctx| {
if let Some(hir_item) = lctx.lower_item(item) {
item_hir_id = Some(hir_item.hir_id);
lctx.insert_item(hir_item);
}
lctx.without_in_scope_lifetime_defs(|lctx| {
if let Some(hir_item) = lctx.lower_item(item) {
item_hir_id = Some(hir_item.hir_id);
lctx.insert_item(hir_item);
}
})
});

if let Some(hir_id) = item_hir_id {
Expand Down Expand Up @@ -134,6 +136,28 @@ impl LoweringContext<'_> {
res
}

// Clears (and restores) the `in_scope_lifetimes` field. Used when
// visiting nested items, which never inherit in-scope lifetimes
// from their surrounding environment.
fn without_in_scope_lifetime_defs<T>(
&mut self,
f: impl FnOnce(&mut LoweringContext<'_>) -> T,
) -> T {
let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);

// this vector is only used when walking over impl headers,
// input types, and the like, and should not be non-empty in
// between items
assert!(self.lifetimes_to_define.is_empty());

let res = f(self);

assert!(self.in_scope_lifetimes.is_empty());
self.in_scope_lifetimes = old_in_scope_lifetimes;

res
}

pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod {
hir::Mod {
inner: m.inner,
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/async-await/nested-in-impl.rs
@@ -0,0 +1,17 @@
// Test that async fn works when nested inside of
// impls with lifetime parameters.
//
// check-pass
// edition:2018

#![feature(async_await)]

struct Foo<'a>(&'a ());

impl<'a> Foo<'a> {
fn test() {
async fn test() {}
}
}

fn main() { }
20 changes: 20 additions & 0 deletions src/test/ui/in-band-lifetimes/nested-items.rs
@@ -0,0 +1,20 @@
// Test that the `'a` from the impl doesn't
// prevent us from creating a `'a` parameter
// on the `blah` function.
//
// check-pass

#![feature(in_band_lifetimes)]

struct Foo<'a> {
x: &'a u32

}

impl Foo<'a> {
fn method(&self) {
fn blah(f: Foo<'a>) { }
}
}

fn main() { }

0 comments on commit e4756e6

Please sign in to comment.