Change:
The following breaks on nightly (see ) With: CC: dtolnay/async-trait
Reduced:
Forgot to mention in case this helps, giving the inner fn a matching lifetime avoids this issue for some reason:
The reason this is happening is that the desugared version of applies all in-scope lifetimes to the returned existential type, which in this case is creating , which is invalid. I'm not sure exactly what the best fix is for this, though, since elided lifetimes in the impl signature are intentionally unnameable. The closest idea I have would be to create some special new lifetime that is but can refer to lifetimes originating from the impl header. cc who may have opinions.
Hmm wouldn't you expect the nested to not inherit anything from its enclosing scopes? Seems like a bug to me that it does? Am I confused about something?
The function in the middle is actually a bit of a source of confusion here, although it does indicate that there's a second bug since we shouldn't be inheriting generics since the nested isn't part of the . The bug I was focusing on is better illustrated by this example: which produces this error: This is because the code is transformed into and in that case does not refer back to the usage from the header.
I see. Indeed, I would expect that, internally, we'd have some way to refer back to the from the impl header. I believe this should be possible, no? In particular, the in impls expands (internally) to for some integer N, which I believe is basically treated like any other named lifetime.
Yep, I would've expected so as well-- I'm not sure why that isn't working, I'd have to take a look.
I was looking and I think the bug lies here: Probably needs to be a instead, or we need to use something else for this purpose.
A closer reading suggests I was mistaken. The lifetimes from the impl should show up in -- includes only the explicitly declared lifetimes written by the user on the impl. I'm not quite sure what the problem is yet.
OK, no, I was correct. When processing impl items, we convert the lifetimes into entries. EDIT: Er, I'm still not entirely sure. Reading more. =)
OK, I have a fix for the method issue, but not the nested async fn item issue.
I forked off for the method issue
I didn't prep a fix for this one yet. It seems obvious that some internal state is not being reset when we enter a new item.
but if you have a chance to investigate, would be appreciated
Presumably the problem is that doesn't "reset" the vector -- it only seems to extend it...
Indeed, in-band lifetimes are broken in the same way. This fails to compile ():
Working on a possible fix
Yep, have a fix.
Inband lifetimes looks similar to fwiw
thanks

Discussion:
/// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked /// against this list to see if it is already in-scope, or if a definition /// needs to be created for it. <del> in_scope_lifetimes: Vec<Ident>, </del> <ins> /// /// We always store a `modern()` version of the param-name in this /// vector. in_scope_lifetimes: Vec<ParamName>, </ins> current_module: NodeId,

return; } <del> if self.in_scope_lifetimes.contains(&ident.modern()) { </del> <ins> if self.in_scope_lifetimes.contains(&ParamName::Plain(ident.modern())) { </ins> return; }

{ let old_len = self.in_scope_lifetimes.len(); let lt_def_names = params.iter().filter_map(|param| match param.kind { <del> GenericParamKind::Lifetime { .. } => Some(param.ident.modern()), </del> <ins> GenericParamKind::Lifetime { .. } => Some(ParamName::Plain(param.ident.modern())), </ins> _ => None, }); self.in_scope_lifetimes.extend(lt_def_names);

let lifetime_params: Vec<(Span, ParamName)> = this.in_scope_lifetimes .iter().cloned() <del> .map(|ident| (ident.span, ParamName::Plain(ident))) </del> <ins> .map(|name| (name.ident().span, name)) </ins> .chain(this.lifetimes_to_define.iter().cloned()) .collect(); <ins> debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes); debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define); debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params); </ins> let generic_params = lifetime_params .iter().cloned()

fn visit_item(&mut self, item: &'tcx Item) { let mut item_hir_id = None; self.lctx.with_hir_id_owner(item.id, |lctx| { <del> if let Some(hir_item) = lctx.lower_item(item) { item_hir_id = Some(hir_item.hir_id); lctx.insert_item(hir_item); } </del> <ins> 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); } }) </ins> }); if let Some(hir_id) = item_hir_id {

_ => &[], }; let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind { <del> hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()), </del> <ins> hir::GenericParamKind::Lifetime { .. } => Some(param.name.modern()), </ins> _ => None, }); self.in_scope_lifetimes.extend(lt_def_names);

res } <ins> // 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 } </ins> pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod { hir::Mod { inner: m.inner,

<ins> // Check that `async fn` inside of an impl with `'_` // in the header compiles correctly. // // Regression test for #63500. // // check-pass // edition:2018 #![feature(async_await)] struct Foo<'a>(&'a u8); impl Foo<'_> { async fn bar() {} } fn main() { } </ins>

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

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