diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ff29d15f1b525..f47815f9bcb0c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2131,6 +2131,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::LifetimeName::Param(param, ParamName::Fresh) } + LifetimeRes::ImplicitObjectLifetimeDefault => { + hir::LifetimeName::ImplicitObjectLifetimeDefault + } LifetimeRes::Infer => hir::LifetimeName::Infer, LifetimeRes::Static => hir::LifetimeName::Static, LifetimeRes::Error => hir::LifetimeName::Error, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 4ef4aad902c68..489305fd44f84 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -765,6 +765,8 @@ pub enum LifetimeRes { /// Id of the introducing place. See `Param`. binder: NodeId, }, + /// FIXME(bgr360): document this. + ImplicitObjectLifetimeDefault, /// This variant is used for anonymous lifetimes that we did not resolve during /// late resolution. Those lifetimes will be inferred by typechecking. Infer, @@ -773,5 +775,8 @@ pub enum LifetimeRes { /// Resolution failure. Error, /// HACK: This is used to recover the NodeId of an elided lifetime. - ElidedAnchor { start: NodeId, end: NodeId }, + ElidedAnchor { + start: NodeId, + end: NodeId, + }, } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6d2ee25df320d..d82cec74b1667 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -584,6 +584,12 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// If it is `true`, then it will be updated when entering a nested function or trait body. in_func_body: bool, + /// State used to know whether we are currently resolving params for a + /// function or closure. + /// + /// Notably, rustc uses this to allow `dyn Trait + '_` in certain cases. + in_func_params: bool, + /// Count the number of places a lifetime is used. lifetime_uses: FxHashMap, } @@ -633,6 +639,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.resolve_local(local); self.diagnostic_metadata.current_let_binding = original; } + #[instrument(level = "trace", skip_all, fields(?ty.kind))] fn visit_ty(&mut self, ty: &'ast Ty) { let prev = self.diagnostic_metadata.current_trait_object; let prev_ty = self.diagnostic_metadata.current_type_path; @@ -922,6 +929,16 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) { self.resolve_lifetime(lifetime, use_ctxt) } + fn visit_param_bound(&mut self, bound: &'ast GenericBound, bound_kind: BoundKind) { + match (bound_kind, bound) { + (BoundKind::TraitObject, GenericBound::Outlives(lifetime @ Lifetime { ident, .. })) + if ident.name == kw::UnderscoreLifetime => + { + self.resolve_anonymous_lifetime_in_trait_object_bounds(lifetime); + } + _ => visit::walk_param_bound(self, bound), + } + } fn visit_generics(&mut self, generics: &'ast Generics) { self.visit_generic_params( @@ -945,8 +962,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } + #[instrument(level = "debug", skip(self))] fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { - debug!("visit_generic_arg({:?})", arg); let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true); match arg { GenericArg::Type(ref ty) => { @@ -1072,8 +1089,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } + #[instrument(level = "debug", skip(self))] fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { - debug!("visit_where_predicate {:?}", p); let previous_value = replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p)); self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { @@ -1172,6 +1189,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { diagnostic_metadata: Box::new(DiagnosticMetadata::default()), // errors at module scope should always be reported in_func_body: false, + in_func_params: false, lifetime_uses: Default::default(), } } @@ -1787,6 +1805,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + /// For backwards compatibility, we need to accept the following: + /// + /// ``` + /// trait AsStr { + /// fn as_str(&self) -> &str; + /// } + /// + /// fn foo(a: &(dyn AsStr + '_)) -> &str { a.as_str() } + /// ``` + /// + /// When we're resolving function parameters, we usually want each elided or + /// anonymous lifetime to result in a new elision candidate, but not in this case. + #[instrument(level = "trace", skip(self))] + fn resolve_anonymous_lifetime_in_trait_object_bounds(&mut self, lifetime: &Lifetime) { + debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); + debug_assert!(self.diagnostic_metadata.current_trait_object.is_some()); + + if self.in_func_params { + self.with_lifetime_rib( + LifetimeRibKind::Elided(LifetimeRes::ImplicitObjectLifetimeDefault), + |this| this.resolve_anonymous_lifetime(lifetime, false), + ); + } else { + self.resolve_anonymous_lifetime(lifetime, false); + } + } + #[instrument(level = "debug", skip(self))] fn record_lifetime_res( &mut self, @@ -1806,7 +1851,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { candidates.push((res, candidate)); } } - LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {} + LifetimeRes::ImplicitObjectLifetimeDefault + | LifetimeRes::Infer + | LifetimeRes::Error + | LifetimeRes::ElidedAnchor { .. } => {} } } @@ -1833,6 +1881,19 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let elision_lifetime = self.resolve_fn_params(has_self, inputs); debug!(?elision_lifetime); + // We might be about to resolve the return type of some + // `fn() -> T`-typed parameter, like: + // + // ``` + // fn foo(f: fn(&str) -> Box) { ... } + // ``` + // + // In that case, we don't want to act like we're resolving function + // parameters. + // + // FIXME(bgr360): test multiple levels of this + let outer_in_params = replace(&mut self.in_func_params, false); + let outer_failures = take(&mut self.diagnostic_metadata.current_elision_failures); let output_rib = if let Ok(res) = elision_lifetime.as_ref() { LifetimeRibKind::Elided(*res) @@ -1846,16 +1907,20 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let Err(failure_info) = elision_lifetime else { bug!() }; self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); } + + self.in_func_params = outer_in_params; } /// Resolve inside function parameters and parameter types. /// Returns the lifetime for elision in fn return type, /// or diagnostic information in case of elision failure. + #[instrument(level = "debug", skip(self, inputs))] fn resolve_fn_params( &mut self, has_self: bool, inputs: impl Iterator, &'ast Ty)>, ) -> Result, Vec)> { + #[derive(Debug)] enum Elision { /// We have not found any candidate. None, @@ -1867,7 +1932,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Err, } - // Save elision state to reinstate it later. + // Save state to reinstate it later. + let outer_in_params = replace(&mut self.in_func_params, true); let outer_candidates = self.lifetime_elision_candidates.take(); // Result of elision. @@ -1890,9 +1956,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.lifetime_elision_candidates = Some(Default::default()); self.visit_ty(ty); let local_candidates = self.lifetime_elision_candidates.take(); + trace!(?local_candidates); if let Some(candidates) = local_candidates { let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect(); + trace!(?distinct); let lifetime_count = distinct.len(); if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { @@ -1947,12 +2015,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { elision_lifetime = Elision::None; } } + trace!(?elision_lifetime); debug!("(resolving function / closure) recorded parameter"); } - // Reinstate elision state. + // Reinstate state. debug_assert_matches!(self.lifetime_elision_candidates, None); self.lifetime_elision_candidates = outer_candidates; + self.in_func_params = outer_in_params; if let Elision::Param(res) | Elision::Self_(res) = elision_lifetime { return Ok(res); @@ -2085,8 +2155,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { true } + #[instrument(level = "debug", skip_all)] fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { - debug!("resolve_adt"); self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, @@ -2156,10 +2226,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + #[instrument(level = "debug", skip_all, fields(name = %item.ident.name, kind = ?item.kind))] fn resolve_item(&mut self, item: &'ast Item) { - let name = item.ident.name; - debug!("(resolving item) resolving {} ({:?})", name, item.kind); - match item.kind { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( @@ -2293,6 +2361,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + #[instrument(level = "debug", skip(self, f))] fn with_generic_param_rib<'c, F>( &'c mut self, params: &'c [GenericParam], @@ -2302,7 +2371,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) where F: FnOnce(&mut Self), { - debug!("with_generic_param_rib"); let LifetimeRibKind::Generics { binder, span: generics_span, kind: generics_kind, .. } = lifetime_kind else { panic!() }; @@ -2337,7 +2405,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { for param in params { let ident = param.ident.normalize_to_macros_2_0(); - debug!("with_generic_param_rib: {}", param.id); + debug!(%param.id); if let GenericParamKind::Lifetime = param.kind && let Some(&original) = seen_lifetimes.get(&ident) @@ -2601,6 +2669,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_self_rib_ns(TypeNS, self_res, f) } + #[instrument(level = "debug", skip_all)] fn resolve_implementation( &mut self, generics: &'ast Generics, @@ -2609,7 +2678,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { item_id: NodeId, impl_items: &'ast [P], ) { - debug!("resolve_implementation"); // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, @@ -2680,6 +2748,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } + #[instrument(level = "debug", skip_all)] fn resolve_impl_item( &mut self, item: &'ast AssocItem, @@ -2688,7 +2757,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { use crate::ResolutionError::*; match &item.kind { AssocItemKind::Const(_, ty, default) => { - debug!("resolve_implementation AssocItemKind::Const"); + debug!("AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait self.check_trait_item( @@ -2719,7 +2788,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } AssocItemKind::Fn(box Fn { generics, .. }) => { - debug!("resolve_implementation AssocItemKind::Fn"); + debug!("AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( &generics.params, @@ -2747,7 +2816,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } AssocItemKind::Type(box TyAlias { generics, .. }) => { - debug!("resolve_implementation AssocItemKind::Type"); + debug!("AssocItemKind::Type"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( &generics.params, @@ -2884,8 +2953,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + #[instrument(level = "debug", skip(self))] fn resolve_local(&mut self, local: &'ast Local) { - debug!("resolving local ({:?})", local); // Resolve the type. walk_list!(self, visit_ty, &local.ty); @@ -3310,6 +3379,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } + #[instrument(level = "debug", skip(self, source), ret)] fn smart_resolve_path_fragment( &mut self, qself: Option<&QSelf>, @@ -3317,10 +3387,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, finalize: Finalize, ) -> PartialRes { - debug!( - "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})", - qself, path, finalize, - ); let ns = source.namespace(); let Finalize { node_id, path_span, .. } = finalize; @@ -3575,6 +3641,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } /// Handles paths that may refer to associated items. + #[instrument(level = "debug", skip(self), ret)] fn resolve_qpath( &mut self, qself: Option<&QSelf>, @@ -3582,11 +3649,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ns: Namespace, finalize: Finalize, ) -> Result, Spanned>> { - debug!( - "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})", - qself, path, ns, finalize, - ); - if let Some(qself) = qself { if qself.position == 0 { // This is a case like `::B`, where there is no @@ -3685,6 +3747,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Ok(Some(result)) } + #[instrument(level = "trace", skip(self, f))] fn with_resolved_label(&mut self, label: Option