From 228def7e2077cbd34931f48006dbb809304ff708 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 1 Apr 2022 16:05:42 +0200 Subject: [PATCH 01/11] Extract AssocItem handling. --- compiler/rustc_resolve/src/late.rs | 297 +++++++++++++---------------- 1 file changed, 131 insertions(+), 166 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 381073a3f6663..b520c155fa22c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1732,72 +1732,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); - - let walk_assoc_item = - |this: &mut Self, - generics: &Generics, - kind, - item: &'ast AssocItem| { - this.with_generic_param_rib( - &generics.params, - AssocItemRibKind, - LifetimeRibKind::Generics { - binder: item.id, - span: generics.span, - kind, - }, - |this| { - visit::walk_assoc_item(this, item, AssocCtxt::Trait) - }, - ); - }; - - this.with_trait_items(items, |this| { - for item in items { - match &item.kind { - AssocItemKind::Const(_, ty, default) => { - this.visit_ty(ty); - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = default { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - None, - |this| this.visit_expr(expr), - ); - } - } - AssocItemKind::Fn(box Fn { generics, .. }) => { - walk_assoc_item( - this, - generics, - LifetimeBinderKind::Function, - item, - ); - } - AssocItemKind::TyAlias(box TyAlias { - generics, - .. - }) => { - walk_assoc_item( - this, - generics, - LifetimeBinderKind::Item, - item, - ); - } - AssocItemKind::MacCall(_) => { - panic!("unexpanded macro in resolve!") - } - }; - } - }); + this.resolve_trait_items(items); }, ); }, @@ -2073,16 +2008,53 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } /// When evaluating a `trait` use its associated types' idents for suggestions in E0412. - fn with_trait_items( - &mut self, - trait_items: &'ast [P], - f: impl FnOnce(&mut Self) -> T, - ) -> T { + fn resolve_trait_items(&mut self, trait_items: &'ast [P]) { let trait_assoc_items = replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items)); - let result = f(self); + + let walk_assoc_item = + |this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| { + this.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind }, + |this| visit::walk_assoc_item(this, item, AssocCtxt::Trait), + ); + }; + + for item in trait_items { + match &item.kind { + AssocItemKind::Const(_, ty, default) => { + self.visit_ty(ty); + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = default { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + self.with_constant_rib( + IsRepeatExpr::No, + HasGenericParams::Yes, + None, + |this| this.visit_expr(expr), + ); + } + } + AssocItemKind::Fn(box Fn { generics, .. }) => { + walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); + } + AssocItemKind::TyAlias(box TyAlias { generics, .. }) => { + walk_assoc_item(self, generics, LifetimeBinderKind::Item, item); + } + AssocItemKind::MacCall(_) => { + panic!("unexpanded macro in resolve!") + } + }; + } + self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items; - result } /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). @@ -2173,99 +2145,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); for item in impl_items { - use crate::ResolutionError::*; - match &item.kind { - AssocItemKind::Const(_default, _ty, _expr) => { - debug!("resolve_implementation AssocItemKind::Const"); - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); - - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.with_constant_rib( - IsRepeatExpr::No, - HasGenericParams::Yes, - None, - |this| { - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::Fn(box Fn { generics, .. }) => { - debug!("resolve_implementation AssocItemKind::Fn"); - // We also need a new scope for the impl item type parameters. - this.with_generic_param_rib( - &generics.params, - AssocItemRibKind, - LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind: LifetimeBinderKind::Function }, - |this| { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - |i, s, c| MethodNotMemberOfTrait(i, s, c), - ); - - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::TyAlias(box TyAlias { - generics, .. - }) => { - debug!("resolve_implementation AssocItemKind::TyAlias"); - // We also need a new scope for the impl item type parameters. - this.with_generic_param_rib( - &generics.params, - AssocItemRibKind, - LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind: LifetimeBinderKind::Item }, - |this| { - // If this is a trait impl, ensure the type - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - TypeNS, - item.span, - |i, s, c| TypeNotMemberOfTrait(i, s, c), - ); - - visit::walk_assoc_item( - this, - item, - AssocCtxt::Impl, - ) - }, - ); - } - AssocItemKind::MacCall(_) => { - panic!("unexpanded macro in resolve!") - } - } + this.resolve_impl_item(&**item); } }); }); @@ -2278,6 +2158,91 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } + fn resolve_impl_item(&mut self, item: &'ast AssocItem) { + use crate::ResolutionError::*; + match &item.kind { + AssocItemKind::Const(_default, _ty, _expr) => { + debug!("resolve_implementation AssocItemKind::Const"); + // If this is a trait impl, ensure the const + // exists in trait + self.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); + + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { + visit::walk_assoc_item(this, item, AssocCtxt::Impl) + }); + } + AssocItemKind::Fn(box Fn { generics, .. }) => { + debug!("resolve_implementation AssocItemKind::Fn"); + // We also need a new scope for the impl item type parameters. + self.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::Function, + }, + |this| { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + |i, s, c| MethodNotMemberOfTrait(i, s, c), + ); + + visit::walk_assoc_item(this, item, AssocCtxt::Impl) + }, + ); + } + AssocItemKind::TyAlias(box TyAlias { generics, .. }) => { + debug!("resolve_implementation AssocItemKind::TyAlias"); + // We also need a new scope for the impl item type parameters. + self.with_generic_param_rib( + &generics.params, + AssocItemRibKind, + LifetimeRibKind::Generics { + binder: item.id, + span: generics.span, + kind: LifetimeBinderKind::Item, + }, + |this| { + // If this is a trait impl, ensure the type + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + TypeNS, + item.span, + |i, s, c| TypeNotMemberOfTrait(i, s, c), + ); + + visit::walk_assoc_item(this, item, AssocCtxt::Impl) + }, + ); + } + AssocItemKind::MacCall(_) => { + panic!("unexpanded macro in resolve!") + } + } + } + fn check_trait_item( &mut self, id: NodeId, From 80c6a1f275b8cc03773f716fc470889bf344ec03 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jun 2022 17:31:49 +0200 Subject: [PATCH 02/11] Rustfmt resolve_implementation. --- compiler/rustc_resolve/src/late.rs | 96 ++++++++++++++++++------------ 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b520c155fa22c..8d454aeff99ef 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2112,50 +2112,68 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) { debug!("resolve_implementation"); // If applicable, create a rib for the type parameters. - self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, binder: item_id, kind: LifetimeBinderKind::ImplBlock }, |this| { - // Dummy self type for better errors if `Self` is used in the trait path. - this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { - this.with_lifetime_rib(LifetimeRibKind::AnonymousCreateParameter(item_id), |this| { - // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(opt_trait_reference.as_ref(), self_type, |this, trait_id| { - let item_def_id = this.r.local_def_id(item_id); - - // Register the trait definitions from here. - if let Some(trait_id) = trait_id { - this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); - } - - let item_def_id = item_def_id.to_def_id(); - let res = - Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) }; - this.with_self_rib(res, |this| { - if let Some(trait_ref) = opt_trait_reference.as_ref() { - // Resolve type arguments in the trait path. - visit::walk_trait_ref(this, trait_ref); - } - // Resolve the self type. - this.visit_ty(self_type); - // Resolve the generic parameters. - this.visit_generics(generics); + self.with_generic_param_rib( + &generics.params, + ItemRibKind(HasGenericParams::Yes), + LifetimeRibKind::Generics { + span: generics.span, + binder: item_id, + kind: LifetimeBinderKind::ImplBlock + }, + |this| { + // Dummy self type for better errors if `Self` is used in the trait path. + this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { + this.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter(item_id), + |this| { + // Resolve the trait reference, if necessary. + this.with_optional_trait_ref( + opt_trait_reference.as_ref(), + self_type, + |this, trait_id| { + let item_def_id = this.r.local_def_id(item_id); + + // Register the trait definitions from here. + if let Some(trait_id) = trait_id { + this.r.trait_impls.entry(trait_id).or_default().push(item_def_id); + } - // Resolve the items within the impl. - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false), - |this| { - this.with_current_self_type(self_type, |this| { - this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { - debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); - for item in impl_items { - this.resolve_impl_item(&**item); - } - }); + let item_def_id = item_def_id.to_def_id(); + let res = Res::SelfTy { + trait_: trait_id, + alias_to: Some((item_def_id, false)), + }; + this.with_self_rib(res, |this| { + if let Some(trait_ref) = opt_trait_reference.as_ref() { + // Resolve type arguments in the trait path. + visit::walk_trait_ref(this, trait_ref); + } + // Resolve the self type. + this.visit_ty(self_type); + // Resolve the generic parameters. + this.visit_generics(generics); + + // Resolve the items within the impl. + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id,false), + |this| { + this.with_current_self_type(self_type, |this| { + this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { + debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + for item in impl_items { + this.resolve_impl_item(&**item); + } + }); + }); + }, + ); }); }, ); - }); - }); + }, + ); }); - }); - }); + }, + ); } fn resolve_impl_item(&mut self, item: &'ast AssocItem) { From 237e267b8050bac6e24d412f0d577c5ca9d57ca1 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jun 2022 18:24:22 +0200 Subject: [PATCH 03/11] Refactor visit_fn. --- compiler/rustc_resolve/src/late.rs | 161 +++++++++++++++----------- src/test/ui/issues/issue-37884.stderr | 2 +- 2 files changed, 97 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 8d454aeff99ef..fce2404950587 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -746,86 +746,117 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.current_function = Some((fn_kind, sp)); } debug!("(resolving function) entering function"); - let declaration = fn_kind.decl(); // Create a value rib for the function. self.with_rib(ValueNS, rib_kind, |this| { // Create a label rib for the function. this.with_label_rib(FnItemRibKind, |this| { - let async_node_id = fn_kind.header().and_then(|h| h.asyncness.opt_return_id()); + match fn_kind { + FnKind::Fn(_, _, sig, _, generics, body) => { + this.visit_generics(generics); - if let FnKind::Fn(_, _, _, _, generics, _) = fn_kind { - this.visit_generics(generics); - } + let declaration = &sig.decl; + let async_node_id = sig.header.asyncness.opt_return_id(); - if let Some(async_node_id) = async_node_id { - // In `async fn`, argument-position elided lifetimes - // must be transformed into fresh generic parameters so that - // they can be applied to the opaque `impl Trait` return type. - this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter(fn_id), - |this| { + // Argument-position elided lifetimes must be transformed into fresh + // generic parameters. This is especially useful for `async fn`, where + // these fresh generic parameters can be applied to the opaque `impl Trait` + // return type. + this.with_lifetime_rib( + if async_node_id.is_some() { + LifetimeRibKind::AnonymousCreateParameter(fn_id) + } else { + LifetimeRibKind::AnonymousPassThrough(fn_id, false) + }, // Add each argument to the rib. - this.resolve_params(&declaration.inputs) - }, - ); - - // Construct the list of in-scope lifetime parameters for async lowering. - // We include all lifetime parameters, either named or "Fresh". - // The order of those parameters does not matter, as long as it is - // deterministic. - let mut extra_lifetime_params = - this.r.extra_lifetime_params_map.get(&fn_id).cloned().unwrap_or_default(); - for rib in this.lifetime_ribs.iter().rev() { - extra_lifetime_params.extend( - rib.bindings - .iter() - .map(|(&ident, &(node_id, res))| (ident, node_id, res)), + |this| this.resolve_params(&declaration.inputs), ); - match rib.kind { - LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter(id) => { - if let Some(earlier_fresh) = - this.r.extra_lifetime_params_map.get(&id) - { - extra_lifetime_params.extend(earlier_fresh); + + // Construct the list of in-scope lifetime parameters for async lowering. + // We include all lifetime parameters, either named or "Fresh". + // The order of those parameters does not matter, as long as it is + // deterministic. + if let Some(async_node_id) = async_node_id { + let mut extra_lifetime_params = this + .r + .extra_lifetime_params_map + .get(&fn_id) + .cloned() + .unwrap_or_default(); + for rib in this.lifetime_ribs.iter().rev() { + extra_lifetime_params.extend( + rib.bindings + .iter() + .map(|(&ident, &(node_id, res))| (ident, node_id, res)), + ); + match rib.kind { + LifetimeRibKind::Item => break, + LifetimeRibKind::AnonymousCreateParameter(binder) => { + if let Some(earlier_fresh) = + this.r.extra_lifetime_params_map.get(&binder) + { + extra_lifetime_params.extend(earlier_fresh); + } + } + _ => {} } } - _ => {} + this.r + .extra_lifetime_params_map + .insert(async_node_id, extra_lifetime_params); } - } - this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); - this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(async_node_id, true), - |this| visit::walk_fn_ret_ty(this, &declaration.output), - ); - } else { - // Add each argument to the rib. - this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), - |this| this.resolve_params(&declaration.inputs), - ); - this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, true), - |this| visit::walk_fn_ret_ty(this, &declaration.output), - ); - }; + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough( + // For async fn, the return type appears inside a custom + // `impl Future` RPIT, so we override the binder's id. + async_node_id.unwrap_or(fn_id), + true, + ), + |this| visit::walk_fn_ret_ty(this, &declaration.output), + ); - // Ignore errors in function bodies if this is rustdoc - // Be sure not to set this until the function signature has been resolved. - let previous_state = replace(&mut this.in_func_body, true); - // Resolve the function body, potentially inside the body of an async closure - this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), - |this| match fn_kind { - FnKind::Fn(.., body) => walk_list!(this, visit_block, body), - FnKind::Closure(_, body) => this.visit_expr(body), - }, - ); + if let Some(body) = body { + // Ignore errors in function bodies if this is rustdoc + // Be sure not to set this until the function signature has been resolved. + let previous_state = replace(&mut this.in_func_body, true); + // Resolve the function body, potentially inside the body of an async closure + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(fn_id, false), + |this| this.visit_block(body), + ); - debug!("(resolving function) leaving function"); - this.in_func_body = previous_state; + debug!("(resolving function) leaving function"); + this.in_func_body = previous_state; + } + } + FnKind::Closure(declaration, body) => { + // Do not attempt to create generic lifetime parameters. + // FIXME: Revisit this decision once `for<>` bounds on closures become a + // thing. + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(fn_id, false), + // Add each argument to the rib. + |this| this.resolve_params(&declaration.inputs), + ); + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(fn_id, true), + |this| visit::walk_fn_ret_ty(this, &declaration.output), + ); + + // Ignore errors in function bodies if this is rustdoc + // Be sure not to set this until the function signature has been resolved. + let previous_state = replace(&mut this.in_func_body, true); + // Resolve the function body, potentially inside the body of an async closure + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(fn_id, false), + |this| this.visit_expr(body), + ); + + debug!("(resolving function) leaving function"); + this.in_func_body = previous_state; + } + } }) }); self.diagnostic_metadata.current_function = previous_value; diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index cd84b6ef48471..9e4e56793ca9e 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -11,7 +11,7 @@ LL | | } | = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` -note: the anonymous lifetime #1 defined here... +note: the anonymous lifetime as defined here... --> $DIR/issue-37884.rs:6:5 | LL | fn next(&'a mut self) -> Option From bf38ba260d43171051249b08cfd9466a518804d6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 May 2022 14:06:26 +0200 Subject: [PATCH 04/11] Separate `AnonymousCreateParameter` and `ReportElidedInPath`. --- compiler/rustc_resolve/src/late.rs | 155 +++++++++++++++++------------ 1 file changed, 93 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fce2404950587..74999067cd44d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -238,14 +238,14 @@ enum LifetimeRibKind { /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. AnonConst, - /// For **Modern** cases, create a new anonymous region parameter - /// and reference that. + /// Create a new anonymous region parameter and reference it. /// - /// For **Dyn Bound** cases, pass responsibility to - /// `resolve_lifetime` code. - /// - /// For **Deprecated** cases, report an error. - AnonymousCreateParameter(NodeId), + /// If `report_in_path`, report an error when encountering lifetime elision in a path: + /// ```ignore + /// struct Foo<'a> { .. } + /// fn foo(x: Foo) {} + /// ``` + AnonymousCreateParameter { binder: NodeId, report_in_path: bool }, /// Give a hard error when either `&` or `'_` is written. Used to /// rule out things like `where T: Foo<'_>`. Does not imply an @@ -764,7 +764,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // return type. this.with_lifetime_rib( if async_node_id.is_some() { - LifetimeRibKind::AnonymousCreateParameter(fn_id) + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: true, + } } else { LifetimeRibKind::AnonymousPassThrough(fn_id, false) }, @@ -791,7 +794,9 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); match rib.kind { LifetimeRibKind::Item => break, - LifetimeRibKind::AnonymousCreateParameter(binder) => { + LifetimeRibKind::AnonymousCreateParameter { + binder, .. + } => { if let Some(earlier_fresh) = this.r.extra_lifetime_params_map.get(&binder) { @@ -1295,7 +1300,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } // An anonymous lifetime is legal here, go ahead. LifetimeRibKind::AnonymousPassThrough(_, false) - | LifetimeRibKind::AnonymousCreateParameter(_) => { + | LifetimeRibKind::AnonymousCreateParameter { .. } => { Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) } _ => None, @@ -1350,8 +1355,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for i in (0..self.lifetime_ribs.len()).rev() { let rib = &mut self.lifetime_ribs[i]; match rib.kind { - LifetimeRibKind::AnonymousCreateParameter(item_node_id) => { - self.create_fresh_lifetime(lifetime.id, lifetime.ident, item_node_id); + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + let res = self.create_fresh_lifetime(lifetime.id, lifetime.ident, binder); + self.record_lifetime_res(lifetime.id, res); return; } LifetimeRibKind::AnonymousReportError => { @@ -1408,7 +1414,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } #[tracing::instrument(level = "debug", skip(self))] - fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) { + fn create_fresh_lifetime( + &mut self, + id: NodeId, + ident: Ident, + item_node_id: NodeId, + ) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); let item_def_id = self.r.local_def_id(item_node_id); @@ -1423,12 +1434,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { debug!(?def_id); let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id }; - self.record_lifetime_res(id, region); self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push(( ident, def_node_id, region, )); + region } #[tracing::instrument(level = "debug", skip(self))] @@ -1471,14 +1482,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let missing = match source { + let mut should_lint = match source { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct(..) => false, }; - let mut res = LifetimeRes::Error; + + let elided_lifetime_span = if segment.has_generic_args { + // If there are brackets, but not generic arguments, then use the opening bracket + segment.args_span.with_hi(segment.args_span.lo() + BytePos(1)) + } else { + // If there are no brackets, use the identifier span. + // HACK: we use find_ancestor_inside to properly suggest elided spans in paths + // originating from macros, since the segment's span might be from a macro arg. + segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span) + }; + let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span); + + let node_ids = self.r.next_node_ids(expected_lifetimes); + self.record_lifetime_res( + segment_id, + LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, + ); + for rib in self.lifetime_ribs.iter().rev() { match rib.kind { // In create-parameter mode we error here because we don't want to support @@ -1487,7 +1515,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // // impl Foo for std::cell::Ref // note lack of '_ // async fn foo(_: std::cell::Ref) { ... } - LifetimeRibKind::AnonymousCreateParameter(_) => { + LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => { + let sess = self.r.session; + let mut err = rustc_errors::struct_span_err!( + sess, + path_span, + E0726, + "implicit elided lifetime not allowed here" + ); + rustc_errors::add_elided_lifetime_in_path_suggestion( + sess.source_map(), + &mut err, + expected_lifetimes, + path_span, + !segment.has_generic_args, + elided_lifetime_span, + ); + err.note("assuming a `'static` lifetime..."); + err.emit(); + should_lint = false; + for i in 0..expected_lifetimes { + let id = node_ids.start.plus(i); + self.record_lifetime_res(id, LifetimeRes::Error); + } + break; + } + LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { + let res = self.create_fresh_lifetime(node_ids.start, ident, binder); + self.record_lifetime_res(node_ids.start, res); + for i in 1..expected_lifetimes { + let id = node_ids.start.plus(i); + let res = self.create_fresh_lifetime(id, ident, binder); + self.record_lifetime_res(id, res); + } break; } // `PassThrough` is the normal case. @@ -1497,62 +1557,30 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // lifetime. Instead, we simply create an implicit lifetime, which will be checked // later, at which point a suitable error will be emitted. LifetimeRibKind::AnonymousPassThrough(binder, _) => { - res = LifetimeRes::Anonymous { binder, elided: true }; + let res = LifetimeRes::Anonymous { binder, elided: true }; + self.record_lifetime_res(node_ids.start, res); + for i in 1..expected_lifetimes { + let id = node_ids.start.plus(i); + self.record_lifetime_res(id, res); + } break; } LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { // FIXME(cjgillot) This resolution is wrong, but this does not matter // since these cases are erroneous anyway. Lifetime resolution should // emit a "missing lifetime specifier" diagnostic. - res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; + let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; + for i in 0..expected_lifetimes { + let id = node_ids.start.plus(i); + self.record_lifetime_res(id, res); + } break; } _ => {} } } - let node_ids = self.r.next_node_ids(expected_lifetimes); - self.record_lifetime_res( - segment_id, - LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, - ); - for i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); - self.record_lifetime_res(id, res); - } - - if !missing { - continue; - } - - let elided_lifetime_span = if segment.has_generic_args { - // If there are brackets, but not generic arguments, then use the opening bracket - segment.args_span.with_hi(segment.args_span.lo() + BytePos(1)) - } else { - // If there are no brackets, use the identifier span. - // HACK: we use find_ancestor_inside to properly suggest elided spans in paths - // originating from macros, since the segment's span might be from a macro arg. - segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span) - }; - if let LifetimeRes::Error = res { - let sess = self.r.session; - let mut err = rustc_errors::struct_span_err!( - sess, - path_span, - E0726, - "implicit elided lifetime not allowed here" - ); - rustc_errors::add_elided_lifetime_in_path_suggestion( - sess.source_map(), - &mut err, - expected_lifetimes, - path_span, - !segment.has_generic_args, - elided_lifetime_span, - ); - err.note("assuming a `'static` lifetime..."); - err.emit(); - } else { + if should_lint { self.r.lint_buffer.buffer_lint_with_diagnostic( lint::builtin::ELIDED_LIFETIMES_IN_PATHS, segment_id, @@ -2155,7 +2183,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Dummy self type for better errors if `Self` is used in the trait path. this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| { this.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter(item_id), + LifetimeRibKind::AnonymousCreateParameter { + binder: item_id, + report_in_path: true + }, |this| { // Resolve the trait reference, if necessary. this.with_optional_trait_ref( From 87c841e19096f065d0e8a320c2c529b9d293da5d Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jun 2022 21:43:02 +0200 Subject: [PATCH 05/11] Remove the `region` terminology. --- compiler/rustc_resolve/src/late.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 74999067cd44d..f260713a18fe7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -238,7 +238,7 @@ enum LifetimeRibKind { /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. AnonConst, - /// Create a new anonymous region parameter and reference it. + /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: /// ```ignore @@ -1279,13 +1279,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for i in &mut indices { let rib = &self.lifetime_ribs[i]; let normalized_ident = ident.normalize_to_macros_2_0(); - if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) { - self.record_lifetime_res(lifetime.id, region); + if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) { + self.record_lifetime_res(lifetime.id, res); - if let LifetimeRes::Param { param, .. } = region { + if let LifetimeRes::Param { param, .. } = res { match self.lifetime_uses.entry(param) { Entry::Vacant(v) => { - debug!("First use of {:?} at {:?}", region, ident.span); + debug!("First use of {:?} at {:?}", res, ident.span); let use_set = self .lifetime_ribs .iter() @@ -1310,7 +1310,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { v.insert(use_set); } Entry::Occupied(mut o) => { - debug!("Many uses of {:?} at {:?}", region, ident.span); + debug!("Many uses of {:?} at {:?}", res, ident.span); *o.get_mut() = LifetimeUseSet::Many; } } @@ -1433,13 +1433,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); debug!(?def_id); - let region = LifetimeRes::Fresh { param: def_id, binder: item_node_id }; + let res = LifetimeRes::Fresh { param: def_id, binder: item_node_id }; self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push(( ident, def_node_id, - region, + res, )); - region + res } #[tracing::instrument(level = "debug", skip(self))] From dc614b90ca9580eb9efd680648af28dce10e58a4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 5 Jun 2022 21:55:30 +0200 Subject: [PATCH 06/11] Make matches exhaustive. --- compiler/rustc_resolve/src/late.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f260713a18fe7..839e0fe1b5061 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1303,7 +1303,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | LifetimeRibKind::AnonymousCreateParameter { .. } => { Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt }) } - _ => None, + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric + | LifetimeRibKind::AnonConst => None, }) .unwrap_or(LifetimeUseSet::Many); debug!(?use_ctxt, ?use_set); @@ -1390,7 +1392,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return; } LifetimeRibKind::Item => break, - _ => {} + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric + | LifetimeRibKind::AnonConst => {} } } // This resolution is wrong, it passes the work to HIR lifetime resolution. @@ -1576,7 +1580,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } break; } - _ => {} + LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric + | LifetimeRibKind::AnonConst => {} } } From bc6a2c11ee34b46a1e2863a8522b6f7c2e4481c3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 6 Jun 2022 09:02:24 +0200 Subject: [PATCH 07/11] Leave the responsibility to create `Fresh` lifetimes to lowering. --- compiler/rustc_ast_lowering/src/item.rs | 11 +++++--- compiler/rustc_ast_lowering/src/lib.rs | 15 +++++++++-- compiler/rustc_hir/src/def.rs | 4 ++- compiler/rustc_resolve/src/late.rs | 34 ++++++++----------------- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 717918116e595..0ef213716945c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1386,16 +1386,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self.lower_generic_params_mut(&generics.params).collect(); + + // Introduce extra lifetimes if late resolution tells us to. + let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); + params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { + self.lifetime_res_to_generic_param(ident, node_id, res) + })); + let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); let where_clause_span = self.lower_span(generics.where_clause.span); let span = self.lower_span(generics.span); let res = f(self); - let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); let impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); - params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) - })); params.extend(impl_trait_defs.into_iter()); let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 4fa2cd5e23bd3..271ead78c5b9b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -731,7 +731,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Param { .. } => { (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) } - LifetimeRes::Fresh { .. } => (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided), + LifetimeRes::Fresh { param, .. } => { + // Late resolution delegates to us the creation of the `LocalDefId`. + let _def_id = self.create_def( + self.current_hir_id_owner, + param, + DefPathData::LifetimeNs(kw::UnderscoreLifetime), + ); + debug!(?_def_id); + + (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided) + } LifetimeRes::Static | LifetimeRes::Error => return None, res => panic!( "Unexpected lifetime resolution {:?} for {:?} at {:?}", @@ -1814,8 +1824,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } hir::LifetimeName::Param(param, p_name) } - LifetimeRes::Fresh { mut param, binder } => { + LifetimeRes::Fresh { param, binder } => { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + let mut param = self.local_def_id(param); if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() { if !captured_lifetimes.binders_to_ignore.contains(&binder) { match captured_lifetimes.captures.entry(param) { diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 3927523f4c6ab..a111355c528d2 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -732,7 +732,9 @@ pub enum LifetimeRes { /// Created a generic parameter for an anonymous lifetime. Fresh { /// Id of the generic parameter that introduced it. - param: LocalDefId, + /// + /// Creating the associated `LocalDefId` is the responsibility of lowering. + param: NodeId, /// Id of the introducing place. See `Param`. binder: NodeId, }, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 839e0fe1b5061..abccb94a9062d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -20,7 +20,6 @@ use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_hir::definitions::DefPathData; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_index::vec::Idx; use rustc_middle::ty::DefIdTree; @@ -1418,31 +1417,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } #[tracing::instrument(level = "debug", skip(self))] - fn create_fresh_lifetime( - &mut self, - id: NodeId, - ident: Ident, - item_node_id: NodeId, - ) -> LifetimeRes { + fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); - let item_def_id = self.r.local_def_id(item_node_id); - let def_node_id = self.r.next_node_id(); - let def_id = self.r.create_def( - item_def_id, - def_node_id, - DefPathData::LifetimeNs(kw::UnderscoreLifetime), - self.parent_scope.expansion.to_expn_id(), - ident.span, - ); - debug!(?def_id); - let res = LifetimeRes::Fresh { param: def_id, binder: item_node_id }; - self.r.extra_lifetime_params_map.entry(item_node_id).or_insert_with(Vec::new).push(( - ident, - def_node_id, - res, - )); + // Leave the responsibility to create the `LocalDefId` to lowering. + let param = self.r.next_node_id(); + let res = LifetimeRes::Fresh { param, binder }; + + // Record the created lifetime parameter so lowering can pick it up and add it to HIR. + self.r + .extra_lifetime_params_map + .entry(binder) + .or_insert_with(Vec::new) + .push((ident, param, res)); res } From 4b79b8bfa139ca5f991aa08b405003f748d3caf6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Fri, 13 May 2022 19:08:57 +0200 Subject: [PATCH 08/11] Only use special async fn case for actual async fns in borrowck diagnostics. --- compiler/rustc_borrowck/src/diagnostics/region_name.rs | 9 ++++++++- src/test/ui/issues/issue-37884.stderr | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index d6b5089712ab4..1db4b902f7150 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -254,6 +254,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// *user* has a name for. In that case, we'll be able to map /// `fr` to a `Region<'tcx>`, and that region will be one of /// named variants. + #[tracing::instrument(level = "trace", skip(self))] fn give_name_from_error_region(&self, fr: RegionVid) -> Option { let error_region = self.to_error_region(fr)?; @@ -290,7 +291,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { if free_region.bound_region.is_named() { // A named region that is actually named. Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) }) - } else { + } else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) { // If we spuriously thought that the region is named, we should let the // system generate a true name for error messages. Currently this can // happen if we have an elided name in an async fn for example: the @@ -301,6 +302,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { name, source: RegionNameSource::AnonRegionFromAsyncFn(span), }) + } else { + None } } @@ -362,6 +365,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | fn foo(x: &u32) { .. } /// ------- fully elaborated type of `x` is `&'1 u32` /// ``` + #[tracing::instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_arguments( &self, fr: RegionVid, @@ -651,6 +655,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | let x = Some(&22); /// - fully elaborated type of `x` is `Option<&'1 u32>` /// ``` + #[tracing::instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( @@ -670,6 +675,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// must be a closure since, in a free fn, such an argument would /// have to either also appear in an argument (if using elision) /// or be early bound (named, not in argument). + #[tracing::instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option { let tcx = self.infcx.tcx; let hir = tcx.hir(); @@ -801,6 +807,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } + #[tracing::instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_yield_ty( &self, fr: RegionVid, diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index 9e4e56793ca9e..cd84b6ef48471 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -11,7 +11,7 @@ LL | | } | = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>` found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>` -note: the anonymous lifetime as defined here... +note: the anonymous lifetime #1 defined here... --> $DIR/issue-37884.rs:6:5 | LL | fn next(&'a mut self) -> Option From 32af719b07217ff89e61a2031500cee138599baa Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 11 May 2022 22:49:39 +0200 Subject: [PATCH 09/11] Always create parameters for functions-like types. --- compiler/rustc_ast_lowering/src/lib.rs | 60 ++++-- compiler/rustc_ast_lowering/src/path.rs | 51 ++--- compiler/rustc_hir/src/def.rs | 3 +- compiler/rustc_resolve/src/late.rs | 193 +++++++++++++----- .../rustc_resolve/src/late/diagnostics.rs | 15 +- compiler/rustc_resolve/src/late/lifetimes.rs | 4 +- compiler/rustc_typeck/src/astconv/mod.rs | 6 +- .../rustc_typeck/src/check/compare_method.rs | 66 +++--- .../generic-associated-types/issue-70304.rs | 2 +- .../issue-70304.stderr | 13 +- .../generic-associated-types/issue-95305.rs | 2 +- .../issue-95305.stderr | 12 +- .../parameter_number_and_kind_impl.stderr | 6 +- .../normalize-under-binder/issue-71955.stderr | 4 +- .../normalize-under-binder/issue-85455.rs | 4 +- .../normalize-under-binder/issue-85455.stderr | 16 +- .../impl-header-lifetime-elision/dyn-trait.rs | 4 + .../dyn-trait.stderr | 2 +- .../elided-lifetime-in-path-in-pat.rs | 13 ++ ...th-anon-regions-using-trait-objects.stderr | 4 +- 20 files changed, 303 insertions(+), 177 deletions(-) create mode 100644 src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 271ead78c5b9b..e8b92eaad5c8d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -223,6 +223,12 @@ impl ResolverAstLoweringExt for ResolverAstLowering { } /// Obtain the list of lifetimes parameters to add to an item. + /// + /// Extra lifetime parameters should only be added in places that can appear + /// as a `binder` in `LifetimeRes`. + /// + /// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring + /// should appear at the enclosing `PolyTraitRef`. fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { self.extra_lifetime_params_map.remove(&id).unwrap_or_default() } @@ -721,6 +727,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Converts a lifetime into a new generic parameter. + #[tracing::instrument(level = "debug", skip(self))] fn lifetime_res_to_generic_param( &mut self, ident: Ident, @@ -787,11 +794,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// Register a binder to be ignored for lifetime capture. #[tracing::instrument(level = "debug", skip(self, f))] #[inline] - fn with_lifetime_binder(&mut self, binder: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_lifetime_binder( + &mut self, + binder: NodeId, + generic_params: &[GenericParam], + f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T, + ) -> T { + let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect(); + let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); + debug!(?extra_lifetimes); + generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { + self.lifetime_res_to_generic_param(ident, node_id, res) + })); + let generic_params = self.arena.alloc_from_iter(generic_params); + debug!(?generic_params); + if let Some(ctxt) = &mut self.captured_lifetimes { ctxt.binders_to_ignore.insert(binder); } - let ret = f(self); + let ret = f(self, generic_params); if let Some(ctxt) = &mut self.captured_lifetimes { ctxt.binders_to_ignore.remove(&binder); } @@ -1188,15 +1209,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime = self.lower_lifetime(®ion); hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) } - TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { - hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params(&f.generic_params), - unsafety: this.lower_unsafety(f.unsafety), - abi: this.lower_extern(f.ext), - decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), - param_names: this.lower_fn_params_to_names(&f.decl), - })) - }), + TyKind::BareFn(ref f) => { + self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| { + hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { + generic_params, + unsafety: this.lower_unsafety(f.unsafety), + abi: this.lower_extern(f.ext), + decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), + param_names: this.lower_fn_params_to_names(&f.decl), + })) + }) + } TyKind::Never => hir::TyKind::Never, TyKind::Tup(ref tys) => hir::TyKind::Tup( self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))), @@ -1963,13 +1986,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, itctx: ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = self.lower_generic_params(&p.bound_generic_params); - - let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| { - this.lower_trait_ref(&p.trait_ref, itctx) - }); - - hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } + self.with_lifetime_binder( + p.trait_ref.ref_id, + &p.bound_generic_params, + |this, bound_generic_params| { + let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx); + hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) } + }, + ) } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index bd95b5850df75..52ba5daf01410 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -191,9 +191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { - ParenthesizedGenericArgs::Ok => { - self.lower_parenthesized_parameter_data(segment.id, data) - } + ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), ParenthesizedGenericArgs::Err => { let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); err.span_label(data.span, "only `Fn` traits may use parentheses"); @@ -351,7 +349,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_parenthesized_parameter_data( &mut self, - id: NodeId, data: &ParenthesizedArgs, ) -> (GenericArgsCtor<'hir>, bool) { // Switch to `PassThrough` mode for anonymous lifetimes; this @@ -359,31 +356,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // a hidden lifetime parameter. This is needed for backwards // compatibility, even in contexts like an impl header where // we generally don't permit such things (see #51008). - self.with_lifetime_binder(id, |this| { - let ParenthesizedArgs { span, inputs, inputs_span, output } = data; - let inputs = this.arena.alloc_from_iter(inputs.iter().map(|ty| { - this.lower_ty_direct( - ty, - ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam), - ) - })); - let output_ty = match output { - FnRetTy::Ty(ty) => this - .lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), - FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])), - }; - let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))]; - let binding = this.output_ty_binding(output_ty.span, output_ty); - ( - GenericArgsCtor { - args, - bindings: arena_vec![this; binding], - parenthesized: true, - span: data.inputs_span, - }, - false, - ) - }) + let ParenthesizedArgs { span, inputs, inputs_span, output } = data; + let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { + self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + })); + let output_ty = match output { + FnRetTy::Ty(ty) => { + self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) + } + FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), + }; + let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))]; + let binding = self.output_ty_binding(output_ty.span, output_ty); + ( + GenericArgsCtor { + args, + bindings: arena_vec![self; binding], + parenthesized: true, + span: data.inputs_span, + }, + false, + ) } /// An associated type binding `Output = $ty`. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index a111355c528d2..d0893cd09d8db 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -722,8 +722,7 @@ pub enum LifetimeRes { /// Id of the introducing place. That can be: /// - an item's id, for the item's generic parameters; /// - a TraitRef's ref_id, identifying the `for<...>` binder; - /// - a BareFn type's id; - /// - a Path's id when this path has parenthesized generic args. + /// - a BareFn type's id. /// /// This information is used for impl-trait lifetime captures, to know when to or not to /// capture any given lifetime. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index abccb94a9062d..08d6134237a49 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -21,7 +21,6 @@ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::{PrimTy, TraitCandidate}; -use rustc_index::vec::Idx; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -240,9 +239,16 @@ enum LifetimeRibKind { /// Create a new anonymous lifetime parameter and reference it. /// /// If `report_in_path`, report an error when encountering lifetime elision in a path: - /// ```ignore - /// struct Foo<'a> { .. } - /// fn foo(x: Foo) {} + /// ```compile_fail + /// struct Foo<'a> { x: &'a () } + /// async fn foo(x: Foo) {} + /// ``` + /// + /// Note: the error should not trigger when the elided lifetime is in a pattern or + /// expression-position path: + /// ``` + /// struct Foo<'a> { x: &'a () } + /// async fn foo(Foo { x: _ }: Foo<'_>) {} /// ``` AnonymousCreateParameter { binder: NodeId, report_in_path: bool }, @@ -634,7 +640,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { |this| { this.visit_generic_params(&bare_fn.generic_params, false); this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(ty.id, false), + LifetimeRibKind::AnonymousCreateParameter { + binder: ty.id, + report_in_path: false, + }, |this| walk_list!(this, visit_param, &bare_fn.decl.inputs), ); this.with_lifetime_rib( @@ -720,15 +729,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) | FnKind::Fn(_, _, sig, _, generics, None) => { + self.visit_fn_header(&sig.header); + self.visit_generics(generics); // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. self.with_lifetime_rib( LifetimeRibKind::AnonymousPassThrough(fn_id, false), - |this| { - this.visit_fn_header(&sig.header); - this.visit_generics(generics); - walk_list!(this, visit_param, &sig.decl.inputs); - }, + |this| walk_list!(this, visit_param, &sig.decl.inputs), ); self.with_lifetime_rib( LifetimeRibKind::AnonymousPassThrough(fn_id, true), @@ -761,15 +768,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // generic parameters. This is especially useful for `async fn`, where // these fresh generic parameters can be applied to the opaque `impl Trait` // return type. + let rib = if async_node_id.is_some() { + // Only emit a hard error for `async fn`, since this kind of + // elision has always been allowed in regular `fn`s. + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: true, + } + } else { + LifetimeRibKind::AnonymousPassThrough(fn_id, false) + }; this.with_lifetime_rib( - if async_node_id.is_some() { - LifetimeRibKind::AnonymousCreateParameter { - binder: fn_id, - report_in_path: true, - } - } else { - LifetimeRibKind::AnonymousPassThrough(fn_id, false) - }, + rib, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); @@ -937,19 +947,66 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.currently_processing_generics = prev; } + fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) { + self.visit_ident(constraint.ident); + if let Some(ref gen_args) = constraint.gen_args { + // Forbid anonymous lifetimes in GAT parameters until proper semantics are decided. + self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + this.visit_generic_args(gen_args.span(), gen_args) + }); + } + match constraint.kind { + AssocConstraintKind::Equality { ref term } => match term { + Term::Ty(ty) => self.visit_ty(ty), + Term::Const(c) => self.visit_anon_const(c), + }, + AssocConstraintKind::Bound { ref bounds } => { + walk_list!(self, visit_param_bound, bounds, BoundKind::Bound); + } + } + } + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) { if let Some(ref args) = path_segment.args { match &**args { GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), - GenericArgs::Parenthesized(ref data) => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, false), - |this| walk_list!(this, visit_ty, &data.inputs), - ); - self.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(path_segment.id, true), - |this| visit::walk_fn_ret_ty(this, &data.output), - ) + GenericArgs::Parenthesized(p_args) => { + // Probe the lifetime ribs to know how to behave. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // We are inside a `PolyTraitRef`. The lifetimes are + // to be intoduced in that (maybe implicit) `for<>` binder. + LifetimeRibKind::Generics { + binder, + kind: LifetimeBinderKind::PolyTrait, + .. + } => { + self.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter { + binder, + report_in_path: false, + }, + |this| walk_list!(this, visit_ty, &p_args.inputs), + ); + self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(binder, true), + |this| visit::walk_fn_ret_ty(this, &p_args.output), + ); + break; + } + // We have nowhere to introduce generics. Code is malformed, + // so use regular lifetime resolution to avoid spurious errors. + LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { + visit::walk_generic_args(self, path_span, args); + break; + } + LifetimeRibKind::AnonymousPassThrough(..) + | LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::AnonConst + | LifetimeRibKind::ConstGeneric => {} + } + } } } } @@ -1474,7 +1531,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { continue; } - let mut should_lint = match source { + let missing = match source { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true, PathSource::Expr(..) | PathSource::Pat @@ -1499,6 +1556,39 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end }, ); + if !missing { + // Do not create a parameter for patterns and expressions. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + LifetimeRibKind::AnonymousPassThrough(binder, _) => { + let res = LifetimeRes::Anonymous { binder, elided: true }; + for id in node_ids { + self.record_lifetime_res(id, res); + } + break; + } + // `LifetimeRes::Error`, which would usually be used in the case of + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // we simply resolve to an implicit lifetime, which will be checked later, at + // which point a suitable error will be emitted. + LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { + // FIXME(cjgillot) This resolution is wrong, but this does not matter + // since these cases are erroneous anyway. Lifetime resolution should + // emit a "missing lifetime specifier" diagnostic. + let res = + LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; + for id in node_ids { + self.record_lifetime_res(id, res); + } + break; + } + _ => {} + } + } + continue; + } + + let mut should_lint = true; for rib in self.lifetime_ribs.iter().rev() { match rib.kind { // In create-parameter mode we error here because we don't want to support @@ -1526,44 +1616,38 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { err.note("assuming a `'static` lifetime..."); err.emit(); should_lint = false; - for i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + + for id in node_ids { self.record_lifetime_res(id, LifetimeRes::Error); } break; } + // Do not create a parameter for patterns and expressions. LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { - let res = self.create_fresh_lifetime(node_ids.start, ident, binder); - self.record_lifetime_res(node_ids.start, res); - for i in 1..expected_lifetimes { - let id = node_ids.start.plus(i); + for id in node_ids { let res = self.create_fresh_lifetime(id, ident, binder); self.record_lifetime_res(id, res); } break; } // `PassThrough` is the normal case. - // `new_error_lifetime`, which would usually be used in the case of `ReportError`, - // is unsuitable here, as these can occur from missing lifetime parameters in a - // `PathSegment`, for which there is no associated `'_` or `&T` with no explicit - // lifetime. Instead, we simply create an implicit lifetime, which will be checked - // later, at which point a suitable error will be emitted. LifetimeRibKind::AnonymousPassThrough(binder, _) => { let res = LifetimeRes::Anonymous { binder, elided: true }; - self.record_lifetime_res(node_ids.start, res); - for i in 1..expected_lifetimes { - let id = node_ids.start.plus(i); + for id in node_ids { self.record_lifetime_res(id, res); } break; } + // `LifetimeRes::Error`, which would usually be used in the case of + // `ReportError`, is unsuitable here, as we don't emit an error yet. Instead, + // we simply resolve to an implicit lifetime, which will be checked later, at + // which point a suitable error will be emitted. LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => { // FIXME(cjgillot) This resolution is wrong, but this does not matter // since these cases are erroneous anyway. Lifetime resolution should // emit a "missing lifetime specifier" diagnostic. let res = LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided: true }; - for i in 0..expected_lifetimes { - let id = node_ids.start.plus(i); + for id in node_ids { self.record_lifetime_res(id, res); } break; @@ -2235,7 +2319,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_impl_item(&mut self, item: &'ast AssocItem) { use crate::ResolutionError::*; match &item.kind { - AssocItemKind::Const(_default, _ty, _expr) => { + AssocItemKind::Const(_, ty, default) => { debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait @@ -2248,14 +2332,17 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |i, s, c| ConstNotMemberOfTrait(i, s, c), ); - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { - visit::walk_assoc_item(this, item, AssocCtxt::Impl) - }); + self.visit_ty(ty); + if let Some(expr) = default { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { + this.visit_expr(expr) + }); + } } AssocItemKind::Fn(box Fn { generics, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1a99bff610a02..15f862e21d751 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2223,9 +2223,18 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ] .contains(&Some(did)) { - let (span, span_type) = match &trait_ref.bound_generic_params { - [] => (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty), - [.., bound] => (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail), + let (span, span_type) = if let Some(bound) = + trait_ref.bound_generic_params.iter().rfind(|param| { + matches!( + param.kind, + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) { + (bound.span.shrink_to_hi(), ForLifetimeSpanType::BoundTail) + } else { + (trait_ref.span.shrink_to_lo(), ForLifetimeSpanType::BoundEmpty) }; self.missing_named_lifetime_spots .push(MissingLifetimeSpot::HigherRanked { span, span_type }); diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 447f4174c10d5..53f6870bdf50a 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -755,7 +755,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let next_early_index = self.next_early_index(); let lifetime_span: Option = c.generic_params.iter().rev().find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(param.span), + GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => { + Some(param.span) + } _ => None, }); let (span, span_type) = if let Some(span) = lifetime_span { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 32bbfd7e33232..9db051dc0112b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2920,13 +2920,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) { for br in referenced_regions.difference(&constrained_regions) { let br_name = match *br { + ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => { + "an anonymous lifetime".to_string() + } ty::BrNamed(_, name) => format!("lifetime `{}`", name), - ty::BrAnon(_) | ty::BrEnv => "an anonymous lifetime".to_string(), }; let mut err = generate_err(&br_name); - if let ty::BrAnon(_) = *br { + if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br { // The only way for an anonymous lifetime to wind up // in the return type but **also** be unconstrained is // if it only appears in "associated types" in the diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index acb2aa44ad5df..95c82a7d2c3d8 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -628,24 +628,40 @@ fn compare_number_of_generics<'tcx>( let mut err_occurred = None; for (kind, trait_count, impl_count) in matchings { if impl_count != trait_count { + let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| { + let mut spans = generics + .params + .iter() + .filter(|p| match p.kind { + hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Elided, + } => { + // A fn can have an arbitrary number of extra elided lifetimes for the + // same signature. + !matches!(kind, ty::AssocKind::Fn) + } + _ => true, + }) + .map(|p| p.span) + .collect::>(); + if spans.is_empty() { + spans = vec![generics.span] + } + spans + }; let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { let trait_item = tcx.hir().expect_trait_item(def_id); - if trait_item.generics.params.is_empty() { - (Some(vec![trait_item.generics.span]), vec![]) - } else { - let arg_spans: Vec = - trait_item.generics.params.iter().map(|p| p.span).collect(); - let impl_trait_spans: Vec = trait_item - .generics - .params - .iter() - .filter_map(|p| match p.kind { - GenericParamKind::Type { synthetic: true, .. } => Some(p.span), - _ => None, - }) - .collect(); - (Some(arg_spans), impl_trait_spans) - } + let arg_spans: Vec = arg_spans(trait_.kind, trait_item.generics); + let impl_trait_spans: Vec = trait_item + .generics + .params + .iter() + .filter_map(|p| match p.kind { + GenericParamKind::Type { synthetic: true, .. } => Some(p.span), + _ => None, + }) + .collect(); + (Some(arg_spans), impl_trait_spans) } else { (trait_span.map(|s| vec![s]), vec![]) }; @@ -660,23 +676,7 @@ fn compare_number_of_generics<'tcx>( _ => None, }) .collect(); - let spans = if impl_item.generics.params.is_empty() { - vec![impl_item.generics.span] - } else { - impl_item - .generics - .params - .iter() - .filter(|p| { - matches!( - p.kind, - hir::GenericParamKind::Type { .. } - | hir::GenericParamKind::Const { .. } - ) - }) - .map(|p| p.span) - .collect::>() - }; + let spans = arg_spans(impl_.kind, impl_item.generics); let span = spans.first().copied(); let mut err = tcx.sess.struct_span_err_with_code( diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index 1c3d166a1af11..c9fd7248a8004 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -45,7 +45,7 @@ where } fn create_doc() -> impl Document = DocCursorImpl<'_>> { - //~^ ERROR: missing lifetime specifier + //~^ ERROR `'_` cannot be used here [E0637] //~| ERROR: missing lifetime specifier DocumentImpl {} } diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index 08efc82c88658..b3881ccb099f0 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,14 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0637]: `'_` cannot be used here --> $DIR/issue-70304.rs:47:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { - | ^^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime - | -LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { - | ~~~~~~~ + | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier --> $DIR/issue-70304.rs:47:61 @@ -24,4 +18,5 @@ LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0637. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs index 9ead347984b0c..2365daada1147 100644 --- a/src/test/ui/generic-associated-types/issue-95305.rs +++ b/src/test/ui/generic-associated-types/issue-95305.rs @@ -9,7 +9,7 @@ trait Foo { } fn foo(x: &impl Foo = u32>) { } - //~^ ERROR missing lifetime specifier + //~^ ERROR `'_` cannot be used here [E0637] fn bar(x: &impl for<'a> Foo = &'_ u32>) { } //~^ ERROR missing lifetime specifier diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr index 2b48378dc4350..8624d880d4ee2 100644 --- a/src/test/ui/generic-associated-types/issue-95305.stderr +++ b/src/test/ui/generic-associated-types/issue-95305.stderr @@ -1,13 +1,8 @@ -error[E0106]: missing lifetime specifier +error[E0637]: `'_` cannot be used here --> $DIR/issue-95305.rs:11:26 | LL | fn foo(x: &impl Foo = u32>) { } - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | fn foo<'a>(x: &impl Foo = u32>) { } - | ++++ ~~ + | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier --> $DIR/issue-95305.rs:14:41 @@ -22,4 +17,5 @@ LL | fn bar(x: &impl for<'a> Foo = &'a u32>) { } error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +Some errors have detailed explanations: E0106, E0637. +For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr index 76d39c88b61c3..1458bf0c4a493 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr @@ -8,7 +8,7 @@ LL | type A = u32; | ^ lifetimes do not match type in trait error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/parameter_number_and_kind_impl.rs:17:16 + --> $DIR/parameter_number_and_kind_impl.rs:17:12 | LL | type B<'a, 'b>; | -- -- @@ -16,7 +16,9 @@ LL | type B<'a, 'b>; | expected 0 type parameters ... LL | type B<'a, T> = Vec; - | ^ found 1 type parameter + | ^^ ^ + | | + | found 1 type parameter error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration --> $DIR/parameter_number_and_kind_impl.rs:19:11 diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr index 1e2575116a85a..0bfa7b3cc7c45 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr @@ -23,7 +23,7 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `FnOnce<(&&str,)>` + = note: expected trait `for<'r, 's> FnOnce<(&'r &'s str,)>` found trait `for<'r> FnOnce<(&'r &str,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 @@ -61,7 +61,7 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `FnOnce<(&Wrapper<'_>,)>` + = note: expected trait `for<'r, 's> FnOnce<(&'r Wrapper<'s>,)>` found trait `for<'r> FnOnce<(&'r Wrapper<'_>,)>` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index fe319e6c8515c..172bf218c0d4c 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -6,8 +6,8 @@ trait SomeTrait<'a> { fn give_me_ice() { callee:: >::Associated>(); - //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] - //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] + //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] + //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] } fn callee>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index 13b68b072403a..ecca4b999e7e8 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -1,24 +1,24 @@ -error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied +error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied --> $DIR/issue-85455.rs:8:5 | LL | callee:: >::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn give_me_ice>() { - | +++++++++++++++ +LL | fn give_me_ice SomeTrait<'r>>() { + | +++++++++++++++++++++++ -error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied +error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied --> $DIR/issue-85455.rs:8:14 | LL | callee:: >::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn give_me_ice>() { - | +++++++++++++++ +LL | fn give_me_ice SomeTrait<'r>>() { + | +++++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs index c508c0ac9d55a..359c08c98d1ab 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.rs @@ -13,6 +13,10 @@ impl StaticTrait for Box { } trait NotStaticTrait { } impl NotStaticTrait for Box { } +// Check that we don't err when the trait has a lifetime parameter. +trait TraitWithLifetime<'a> { } +impl NotStaticTrait for &dyn TraitWithLifetime<'_> { } + fn static_val(_: T) { } diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index 88c260b18cbb0..762698c4fc141 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -1,5 +1,5 @@ error[E0521]: borrowed data escapes outside of function - --> $DIR/dyn-trait.rs:20:5 + --> $DIR/dyn-trait.rs:24:5 | LL | fn with_dyn_debug_static<'a>(x: Box) { | -- - `x` is a reference that is only valid in the function body diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs new file mode 100644 index 0000000000000..ff84d25114960 --- /dev/null +++ b/src/test/ui/lifetimes/elided-lifetime-in-path-in-pat.rs @@ -0,0 +1,13 @@ +// check-pass + +struct Foo<'a> { + x: &'a (), +} + +// The lifetime in pattern-position `Foo` is elided. +// Verify that lowering does not create an independent lifetime parameter for it. +fn foo<'a>(Foo { x }: Foo<'a>) { + *x +} + +fn main() {} diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr index cce0a31bfbbf1..d85ea6529f628 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.stderr @@ -10,8 +10,8 @@ LL | y.push(z); | help: consider introducing a named lifetime parameter | -LL | fn foo<'a>(x:Box , y: Vec<&u8>, z: &u8) { - | ++++ ++ ++ +LL | fn foo<'a>(x:Box , y: Vec<&'a u8>, z: &'a u8) { + | ++++ ++ ++ error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 From 7437136f0eac3f2ee58de08a784b1e9eae42b619 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 23 May 2022 15:50:02 +0200 Subject: [PATCH 10/11] Use CreateParameter mode for closures too. --- compiler/rustc_ast_lowering/src/expr.rs | 57 +++++++++------- compiler/rustc_hir/src/hir.rs | 3 +- compiler/rustc_hir/src/intravisit.rs | 6 +- compiler/rustc_hir_pretty/src/lib.rs | 2 + compiler/rustc_resolve/src/late.rs | 15 +++-- compiler/rustc_resolve/src/late/lifetimes.rs | 69 +++++++++----------- 6 files changed, 85 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 095a4b26a860f..3babe73030a45 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -165,6 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let Async::Yes { closure_id, .. } = asyncness { self.lower_expr_async_closure( capture_clause, + e.id, closure_id, decl, body, @@ -173,6 +174,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { self.lower_expr_closure( capture_clause, + e.id, movability, decl, body, @@ -604,6 +606,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `static |_task_context| -> { body }`: let generator_kind = hir::ExprKind::Closure { capture_clause, + bound_generic_params: &[], fn_decl, body, fn_decl_span: self.lower_span(span), @@ -828,6 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, capture_clause: CaptureBy, + closure_id: NodeId, movability: Movability, decl: &FnDecl, body: &Expr, @@ -848,16 +852,19 @@ impl<'hir> LoweringContext<'_, 'hir> { (body_id, generator_option) }); - // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None); - - hir::ExprKind::Closure { - capture_clause, - fn_decl, - body, - fn_decl_span: self.lower_span(fn_decl_span), - movability: generator_option, - } + self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| { + // Lower outside new scope to preserve `is_in_loop_condition`. + let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None); + + hir::ExprKind::Closure { + capture_clause, + bound_generic_params, + fn_decl, + body, + fn_decl_span: this.lower_span(fn_decl_span), + movability: generator_option, + } + }) } fn generator_movability_for_fn( @@ -897,6 +904,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, capture_clause: CaptureBy, closure_id: NodeId, + inner_closure_id: NodeId, decl: &FnDecl, body: &Expr, fn_decl_span: Span, @@ -927,7 +935,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let FnRetTy::Ty(ty) = &decl.output { Some(ty.clone()) } else { None }; let async_body = this.make_async_expr( capture_clause, - closure_id, + inner_closure_id, async_ret_ty, body.span, hir::AsyncGeneratorKind::Closure, @@ -938,18 +946,21 @@ impl<'hir> LoweringContext<'_, 'hir> { body_id }); - // We need to lower the declaration outside the new scope, because we - // have to conserve the state of being inside a loop condition for the - // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); - - hir::ExprKind::Closure { - capture_clause, - fn_decl, - body, - fn_decl_span: self.lower_span(fn_decl_span), - movability: None, - } + self.with_lifetime_binder(closure_id, &[], |this, bound_generic_params| { + // We need to lower the declaration outside the new scope, because we + // have to conserve the state of being inside a loop condition for the + // closure argument types. + let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); + + hir::ExprKind::Closure { + capture_clause, + bound_generic_params, + fn_decl, + body, + fn_decl_span: this.lower_span(fn_decl_span), + movability: None, + } + }) } /// Destructure the LHS of complex assignments. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 5a06f8eab7ec9..a7fc59255d79a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1932,6 +1932,7 @@ pub enum ExprKind<'hir> { /// `Option`. Closure { capture_clause: CaptureBy, + bound_generic_params: &'hir [GenericParam<'hir>], fn_decl: &'hir FnDecl<'hir>, body: BodyId, fn_decl_span: Span, @@ -3480,7 +3481,7 @@ impl<'hir> Node<'hir> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { rustc_data_structures::static_assert_size!(super::Block<'static>, 48); - rustc_data_structures::static_assert_size!(super::Expr<'static>, 56); + rustc_data_structures::static_assert_size!(super::Expr<'static>, 64); rustc_data_structures::static_assert_size!(super::Pat<'static>, 88); rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index cce5aa9f7324d..e68274e2ad978 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1169,12 +1169,16 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_arm, arms); } ExprKind::Closure { + bound_generic_params, ref fn_decl, body, capture_clause: _, fn_decl_span: _, movability: _, - } => visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id), + } => { + walk_list!(visitor, visit_generic_param, bound_generic_params); + visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id) + } ExprKind::Block(ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7317ce7335aa5..7bf91df9f760b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1459,11 +1459,13 @@ impl<'a> State<'a> { } hir::ExprKind::Closure { capture_clause, + bound_generic_params, ref fn_decl, body, fn_decl_span: _, movability: _, } => { + self.print_formal_generic_params(bound_generic_params); self.print_capture_clause(capture_clause); self.print_closure_params(&fn_decl, body); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 08d6134237a49..e36f55b2e0237 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -845,11 +845,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } FnKind::Closure(declaration, body) => { - // Do not attempt to create generic lifetime parameters. - // FIXME: Revisit this decision once `for<>` bounds on closures become a - // thing. + // We do not have any explicit generic lifetime parameter. + // FIXME(rfc3216): Change when implementing `for<>` bounds on closures. this.with_lifetime_rib( - LifetimeRibKind::AnonymousPassThrough(fn_id, false), + LifetimeRibKind::AnonymousCreateParameter { + binder: fn_id, + report_in_path: false, + }, // Add each argument to the rib. |this| this.resolve_params(&declaration.inputs), ); @@ -1582,7 +1584,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } break; } - _ => {} + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::Generics { .. } + | LifetimeRibKind::ConstGeneric + | LifetimeRibKind::AnonConst => {} } } continue; diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 53f6870bdf50a..172dc7ffe959e 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -29,8 +29,6 @@ use std::cell::Cell; use std::fmt; use std::mem::take; -use tracing::{debug, span, Level}; - trait RegionExt { fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (LocalDefId, Region); @@ -572,41 +570,38 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); } - fn visit_fn( - &mut self, - fk: intravisit::FnKind<'tcx>, - fd: &'tcx hir::FnDecl<'tcx>, - b: hir::BodyId, - s: rustc_span::Span, - hir_id: hir::HirId, - ) { - let name = match fk { - intravisit::FnKind::ItemFn(id, _, _) => id.name, - intravisit::FnKind::Method(id, _) => id.name, - intravisit::FnKind::Closure => sym::closure, - }; - let name = name.as_str(); - let span = span!(Level::DEBUG, "visit_fn", name); - let _enter = span.enter(); - match fk { - // Any `Binders` are handled elsewhere - intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => { - intravisit::walk_fn(self, fk, fd, b, s, hir_id) - } - intravisit::FnKind::Closure => { - self.map.late_bound_vars.insert(hir_id, vec![]); - let scope = Scope::Binder { - hir_id, - lifetimes: FxIndexMap::default(), - next_early_index: self.next_early_index(), - s: self.scope, - opaque_type_parent: false, - scope_type: BinderScopeType::Normal, - allow_late_bound: true, - where_bound_origin: None, - }; - self.with(scope, move |this| intravisit::walk_fn(this, fk, fd, b, s, hir_id)); - } + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Closure { bound_generic_params, .. } = e.kind { + let next_early_index = self.next_early_index(); + let (lifetimes, binders): (FxIndexMap, Vec<_>) = + bound_generic_params + .iter() + .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param); + let r = late_region_as_bound_region(self.tcx, &pair.1); + (pair, r) + }) + .unzip(); + self.map.late_bound_vars.insert(e.hir_id, binders); + let scope = Scope::Binder { + hir_id: e.hir_id, + lifetimes, + s: self.scope, + next_early_index, + opaque_type_parent: false, + scope_type: BinderScopeType::Normal, + allow_late_bound: true, + where_bound_origin: None, + }; + self.with(scope, |this| { + // a closure has no bounds, so everything + // contained within is scoped within its binder. + intravisit::walk_expr(this, e) + }); + } else { + intravisit::walk_expr(self, e) } } From 576661cb5f4cdcf2ae56f5b210db4b2ef19e0184 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 4 Jun 2022 11:53:34 +0200 Subject: [PATCH 11/11] Rustdoc fallout. --- src/librustdoc/clean/mod.rs | 58 +++++++++++++++++++---------------- src/librustdoc/clean/utils.rs | 9 ++---- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fd30691c32489..9e5c4afc717a7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -222,10 +222,15 @@ impl<'tcx> Clean<'tcx, Option> for ty::Region<'tcx> { match **self { ty::ReStatic => Some(Lifetime::statik()), ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => { - Some(Lifetime(name)) + if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None } + } + ty::ReEarlyBound(ref data) => { + if data.name != kw::UnderscoreLifetime { + Some(Lifetime(data.name)) + } else { + None + } } - ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)), - ty::ReLateBound(..) | ty::ReFree(..) | ty::ReVar(..) @@ -530,29 +535,25 @@ fn clean_generic_param<'tcx>( GenericParamDef { name, kind } } +/// Synthetic type-parameters are inserted after normal ones. +/// In order for normal parameters to be able to refer to synthetic ones, +/// scans them first. +fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool { + match param.kind { + hir::GenericParamKind::Type { synthetic, .. } => synthetic, + _ => false, + } +} + +/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. +/// +/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information. +fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { + matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }) +} + impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics { - // Synthetic type-parameters are inserted after normal ones. - // In order for normal parameters to be able to refer to synthetic ones, - // scans them first. - fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool { - match param.kind { - hir::GenericParamKind::Type { synthetic, .. } => synthetic, - _ => false, - } - } - /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. - /// - /// See [`lifetime_to_generic_param`] in [`rustc_ast_lowering`] for more information. - /// - /// [`lifetime_to_generic_param`]: rustc_ast_lowering::LoweringContext::lifetime_to_generic_param - fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { - matches!( - param.kind, - hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided } - ) - } - let impl_trait_params = self .params .iter() @@ -991,6 +992,7 @@ impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> { generic_params: self .bound_generic_params .iter() + .filter(|p| !is_elided_lifetime(p)) .map(|x| clean_generic_param(cx, None, x)) .collect(), } @@ -1865,8 +1867,12 @@ impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generic_params = - self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect(); + let generic_params = self + .generic_params + .iter() + .filter(|p| !is_elided_lifetime(p)) + .map(|x| clean_generic_param(cx, None, x)) + .collect(); let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names); let decl = clean_fn_decl_with_args(cx, self.decl, args); (generic_params, decl) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 41ab0e9377df6..16574f94c00e9 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -84,12 +84,9 @@ pub(crate) fn substs_to_args<'tcx>( let mut ret_val = Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 })); ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() { - GenericArgKind::Lifetime(lt) => match *lt { - ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => { - Some(GenericArg::Lifetime(Lifetime::elided())) - } - _ => lt.clean(cx).map(GenericArg::Lifetime), - }, + GenericArgKind::Lifetime(lt) => { + Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided()))) + } GenericArgKind::Type(_) if skip_first => { skip_first = false; None