clear in-scope lifetimes for nested items in HIR lowering

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.
This commit is contained in:
Niko Matsakis 2019-08-12 21:08:32 -04:00
parent a02a171e6a
commit e4756e6b07
3 changed files with 65 additions and 4 deletions

View File

@ -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| {
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 {
@ -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,

View File

@ -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() { }

View File

@ -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() { }