diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9442e0f1a1f35..37ae41fabf987 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -53,7 +53,6 @@ impl<'hir> LoweringContext<'_, 'hir> { e.span, seg, ParamMode::Optional, - 0, ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 5eab21bf79a90..5a7ecb47dbeec 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -30,6 +30,7 @@ pub(super) struct NodeCollector<'a, 'hir> { definitions: &'a definitions::Definitions, } +#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))] pub(super) fn index_hir<'hir>( sess: &Session, definitions: &definitions::Definitions, @@ -65,6 +66,7 @@ pub(super) fn index_hir<'hir>( } impl<'a, 'hir> NodeCollector<'a, 'hir> { + #[tracing::instrument(level = "debug", skip(self))] fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { debug_assert_eq!(self.owner, hir_id.owner); debug_assert_ne!(hir_id.local_id.as_u32(), 0); @@ -138,8 +140,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + #[tracing::instrument(level = "debug", skip(self))] fn visit_item(&mut self, i: &'hir Item<'hir>) { - debug!("visit_item: {:?}", i); debug_assert_eq!(i.def_id, self.owner); self.with_parent(i.hir_id(), |this| { if let ItemKind::Struct(ref struct_def, _) = i.kind { @@ -152,6 +154,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + #[tracing::instrument(level = "debug", skip(self))] fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { debug_assert_eq!(fi.def_id, self.owner); self.with_parent(fi.hir_id(), |this| { @@ -170,6 +173,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }) } + #[tracing::instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { debug_assert_eq!(ti.def_id, self.owner); self.with_parent(ti.hir_id(), |this| { @@ -177,6 +181,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + #[tracing::instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { debug_assert_eq!(ii.def_id, self.owner); self.with_parent(ii.hir_id(), |this| { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a8bd8c92a41c4..90339f8ee2b69 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,11 +1,11 @@ -use super::{AnonymousLifetimeMode, LoweringContext, ParamMode}; use super::{AstOwner, ImplTraitContext, ImplTraitPosition, ResolverAstLowering}; +use super::{LoweringContext, ParamMode}; use crate::{Arena, FnDeclKind}; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -81,13 +81,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { is_in_loop_condition: false, is_in_trait_impl: false, is_in_dyn_type: false, - anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough, generator_kind: None, task_context: None, current_item: None, - lifetimes_to_define: Vec::new(), - is_collecting_anonymous_lifetimes: None, - in_scope_lifetimes: Vec::new(), + captured_lifetimes: None, allow_try_trait: Some([sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), @@ -143,32 +140,14 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { LocalDefId { local_def_index } }; - let parent_hir = self.lower_node(parent_id).unwrap().node().expect_item(); + let parent_hir = self.lower_node(parent_id).unwrap(); self.with_lctx(item.id, |lctx| { // Evaluate with the lifetimes in `params` in-scope. // This is used to track which lifetimes have already been defined, // and which need to be replicated when lowering an async fn. - match parent_hir.kind { - hir::ItemKind::Impl(hir::Impl { ref of_trait, ref generics, .. }) => { + match parent_hir.node().expect_item().kind { + hir::ItemKind::Impl(hir::Impl { ref of_trait, .. }) => { lctx.is_in_trait_impl = of_trait.is_some(); - lctx.in_scope_lifetimes = generics - .params - .iter() - .filter(|param| { - matches!(param.kind, hir::GenericParamKind::Lifetime { .. }) - }) - .map(|param| param.name) - .collect(); - } - hir::ItemKind::Trait(_, _, ref generics, ..) => { - lctx.in_scope_lifetimes = generics - .params - .iter() - .filter(|param| { - matches!(param.kind, hir::GenericParamKind::Lifetime { .. }) - }) - .map(|param| param.name) - .collect(); } _ => {} }; @@ -276,7 +255,6 @@ impl<'hir> LoweringContext<'_, 'hir> { ref body, .. }) => { - let fn_def_id = self.resolver.local_def_id(id); self.with_new_scopes(|this| { this.current_item = Some(ident.span); @@ -288,20 +266,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let body_id = this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); - let (generics, decl) = this.add_in_band_defs( - generics, - fn_def_id, - AnonymousLifetimeMode::PassThrough, - |this, idty| { + let (generics, decl) = + this.add_implicit_generics(generics, id, |this, idty| { let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl( - &decl, - Some((fn_def_id, idty)), - FnDeclKind::Fn, - ret_id, - ) - }, - ); + this.lower_fn_decl(&decl, Some((id, idty)), FnDeclKind::Fn, ret_id) + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(header), @@ -339,12 +308,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // type Foo = Foo1 // opaque type Foo1: Trait - let ty = self.lower_ty( - ty, - ImplTraitContext::TypeAliasesOpaqueTy { - capturable_lifetimes: &mut FxHashSet::default(), - }, - ); + let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy); let mut generics = generics.clone(); add_ty_alias_where_clause(&mut generics, where_clauses, true); let generics = self.lower_generics( @@ -419,12 +383,8 @@ impl<'hir> LoweringContext<'_, 'hir> { // method, it will not be considered an in-band // lifetime to be added, but rather a reference to a // parent lifetime. - let lowered_trait_def_id = hir_id.expect_owner(); - let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs( - ast_generics, - lowered_trait_def_id, - AnonymousLifetimeMode::CreateParameter, - |this, _| { + let (generics, (trait_ref, lowered_ty)) = + self.add_implicit_generics(ast_generics, id, |this, _| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, @@ -436,16 +396,12 @@ impl<'hir> LoweringContext<'_, 'hir> { .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (trait_ref, lowered_ty) - }, - ); - - let new_impl_items = - self.with_in_scope_lifetime_defs(&ast_generics.params, |this| { - this.arena.alloc_from_iter( - impl_items.iter().map(|item| this.lower_impl_item_ref(item)), - ) }); + let new_impl_items = self + .arena + .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item))); + // `defaultness.has_value()` is never called for an `impl`, always `true` in order // to not cause an assertion failure inside the `lower_defaultness` function. let has_val = true; @@ -750,18 +706,14 @@ impl<'hir> LoweringContext<'_, 'hir> { kind: match i.kind { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { let fdec = &sig.decl; - let (generics, (fn_dec, fn_args)) = self.add_in_band_defs( - generics, - def_id, - AnonymousLifetimeMode::PassThrough, - |this, _| { + let (generics, (fn_dec, fn_args)) = + self.add_implicit_generics(generics, i.id, |this, _| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None), this.lower_fn_params_to_names(fdec), ) - }, - ); + }); hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } @@ -868,13 +820,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => { let names = self.lower_fn_params_to_names(&sig.decl); - let (generics, sig) = self.lower_method_sig( - generics, - sig, - trait_item_def_id, - FnDeclKind::Trait, - None, - ); + let (generics, sig) = + self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names))) } AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => { @@ -884,7 +831,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, sig) = self.lower_method_sig( generics, sig, - trait_item_def_id, + i.id, FnDeclKind::Trait, asyncness.opt_return_id(), ); @@ -958,8 +905,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> { - let impl_item_def_id = self.resolver.local_def_id(i.id); - let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); @@ -976,7 +921,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, sig) = self.lower_method_sig( generics, sig, - impl_item_def_id, + i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, asyncness.opt_return_id(), ); @@ -996,12 +941,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::TyAlias(ty) } Some(ty) => { - let ty = self.lower_ty( - ty, - ImplTraitContext::TypeAliasesOpaqueTy { - capturable_lifetimes: &mut FxHashSet::default(), - }, - ); + let ty = self.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy); hir::ImplItemKind::TyAlias(ty) } }; @@ -1363,17 +1303,14 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, sig: &FnSig, - fn_def_id: LocalDefId, + id: NodeId, kind: FnDeclKind, is_async: Option, ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); - let (generics, decl) = self.add_in_band_defs( - generics, - fn_def_id, - AnonymousLifetimeMode::PassThrough, - |this, idty| this.lower_fn_decl(&sig.decl, Some((fn_def_id, idty)), kind, is_async), - ); + let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty| { + this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1498,14 +1435,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> { - self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { - hir::WhereClause { - predicates: this.arena.alloc_from_iter( - wc.predicates.iter().map(|predicate| this.lower_where_predicate(predicate)), - ), - span: this.lower_span(wc.span), - } - }) + hir::WhereClause { + predicates: self.arena.alloc_from_iter( + wc.predicates.iter().map(|predicate| self.lower_where_predicate(predicate)), + ), + span: self.lower_span(wc.span), + } } fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { @@ -1515,24 +1450,20 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounded_ty, ref bounds, span, - }) => self.with_in_scope_lifetime_defs(&bound_generic_params, |this| { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: this.lower_generic_params( - bound_generic_params, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - ), - bounded_ty: this.lower_ty( - bounded_ty, - ImplTraitContext::Disallowed(ImplTraitPosition::Type), - ), - bounds: this.arena.alloc_from_iter(bounds.iter().map(|bound| { - this.lower_param_bound( - bound, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), - ) - })), - span: this.lower_span(span), - }) + }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_generic_params: self.lower_generic_params( + bound_generic_params, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), + bounded_ty: self + .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { + self.lower_param_bound( + bound, + ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ) + })), + span: self.lower_span(span), }), WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9cb205074e7ea..b71d81f11da8b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,6 +32,7 @@ #![feature(crate_visibility_modifier)] #![feature(box_patterns)] +#![feature(let_chains)] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] @@ -53,7 +54,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; -use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; @@ -122,27 +122,8 @@ struct LoweringContext<'a, 'hir: 'a> { is_in_trait_impl: bool, is_in_dyn_type: bool, - /// What to do when we encounter an "anonymous lifetime - /// reference". The term "anonymous" is meant to encompass both - /// `'_` lifetimes as well as fully elided cases where nothing is - /// written at all (e.g., `&T` or `std::cell::Ref`). - anonymous_lifetime_mode: AnonymousLifetimeMode, - - /// Used to create lifetime definitions for anonymous lifetimes. - /// When an anonymous lifetime is encountered in a function or impl header and - /// requires to create a fresh lifetime parameter, it is added - /// to this list. The results of this list are then added to the list of - /// lifetime definitions in the corresponding impl or function generics. - lifetimes_to_define: Vec<(Span, NodeId)>, - - /// If anonymous lifetimes are being collected, this field holds the parent - /// `LocalDefId` to create the fresh lifetime parameters' `LocalDefId`. - is_collecting_anonymous_lifetimes: Option, - - /// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB. - /// We always store a `normalize_to_macros_2_0()` version of the param-name in this - /// vector. - in_scope_lifetimes: Vec, + /// Used to handle lifetimes appearing in impl-traits. + captured_lifetimes: Option, current_hir_id_owner: LocalDefId, item_local_id_counter: hir::ItemLocalId, @@ -157,6 +138,68 @@ struct LoweringContext<'a, 'hir: 'a> { allow_into_future: Option>, } +/// Resolution for a lifetime appearing in a type. +#[derive(Copy, Clone, Debug)] +pub enum LifetimeRes { + /// Successfully linked the lifetime to a generic parameter. + Param { + /// Id of the generic parameter that introduced it. + param: LocalDefId, + /// 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. + /// + /// This information is used for impl-trait lifetime captures, to know when to or not to + /// capture any given lifetime. + binder: NodeId, + }, + /// Created a generic parameter for an anonymous lifetime. + Fresh { + /// Id of the generic parameter that introduced it. + param: LocalDefId, + /// Id of the introducing place. See `Param`. + binder: NodeId, + }, + /// This variant is used for anonymous lifetimes that we did not resolve during + /// late resolution. Shifting the work to the HIR lifetime resolver. + Anonymous { + /// Id of the introducing place. See `Param`. + binder: NodeId, + /// Whether this lifetime was spelled or elided. + elided: bool, + }, + /// Explicit `'static` lifetime. + Static, + /// Resolution failure. + Error, + /// HACK: This is used to recover the NodeId of an elided lifetime. + ElidedAnchor { start: NodeId, end: NodeId }, +} + +/// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so +/// to point to the lifetime parameter impl-trait will generate. +/// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not* +/// to rebind the introduced lifetimes. +#[derive(Debug)] +struct LifetimeCaptureContext { + /// parent def_id for new definitions + parent_def_id: LocalDefId, + /// Set of lifetimes to rebind. + captures: FxHashMap< + LocalDefId, // original parameter id + ( + Span, // Span + NodeId, // synthetized parameter id + ParamName, // parameter name + LifetimeRes, // original resolution + ), + >, + /// Traversed binders. The ids in this set should *not* be rebound. + binders_to_ignore: FxHashSet, +} + pub trait ResolverAstLowering { fn def_key(&self, id: DefId) -> DefKey; @@ -175,6 +218,12 @@ pub trait ResolverAstLowering { /// Obtains resolution for a label with the given `NodeId`. fn get_label_res(&self, id: NodeId) -> Option; + /// Obtains resolution for a lifetime with the given `NodeId`. + fn get_lifetime_res(&self, id: NodeId) -> Option; + + /// Obtain the list of lifetimes parameters to add to an item. + fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; + fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; fn definitions(&self) -> &Definitions; @@ -217,29 +266,11 @@ enum ImplTraitContext<'b, 'a> { /// equivalent to a new opaque type like `type T = impl Debug; fn foo() -> T`. /// ReturnPositionOpaqueTy { - /// `DefId` for the parent function, used to look up necessary - /// information later. - fn_def_id: LocalDefId, /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, origin: hir::OpaqueTyOrigin, }, /// Impl trait in type aliases. - TypeAliasesOpaqueTy { - /// Set of lifetimes that this opaque type can capture, if it uses - /// them. This includes lifetimes bound since we entered this context. - /// For example: - /// - /// ``` - /// type A<'b> = impl for<'a> Trait<'a, Out = impl Sized + 'a>; - /// ``` - /// - /// Here the inner opaque type captures `'a` because it uses it. It doesn't - /// need to capture `'b` because it already inherits the lifetime - /// parameter from `A`. - // FIXME(impl_trait): but `required_region_bounds` will ICE later - // anyway. - capturable_lifetimes: &'b mut FxHashSet, - }, + TypeAliasesOpaqueTy, /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), } @@ -273,12 +304,8 @@ impl<'a> ImplTraitContext<'_, 'a> { use self::ImplTraitContext::*; match self { Universal(params, parent) => Universal(params, *parent), - ReturnPositionOpaqueTy { fn_def_id, origin } => { - ReturnPositionOpaqueTy { fn_def_id: *fn_def_id, origin: *origin } - } - TypeAliasesOpaqueTy { capturable_lifetimes } => { - TypeAliasesOpaqueTy { capturable_lifetimes } - } + ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin }, + TypeAliasesOpaqueTy => TypeAliasesOpaqueTy, Disallowed(pos) => Disallowed(*pos), } } @@ -453,56 +480,6 @@ enum ParenthesizedGenericArgs { Err, } -/// What to do when we encounter an **anonymous** lifetime -/// reference. Anonymous lifetime references come in two flavors. You -/// have implicit, or fully elided, references to lifetimes, like the -/// one in `&T` or `Ref`, and you have `'_` lifetimes, like `&'_ T` -/// or `Ref<'_, T>`. These often behave the same, but not always: -/// -/// - certain usages of implicit references are deprecated, like -/// `Ref`, and we sometimes just give hard errors in those cases -/// as well. -/// - for object bounds there is a difference: `Box` is not -/// the same as `Box`. -/// -/// We describe the effects of the various modes in terms of three cases: -/// -/// - **Modern** -- includes all uses of `'_`, but also the lifetime arg -/// of a `&` (e.g., the missing lifetime in something like `&T`) -/// - **Dyn Bound** -- if you have something like `Box`, -/// there is an elided lifetime bound (`Box`). These -/// elided bounds follow special rules. Note that this only covers -/// cases where *nothing* is written; the `'_` in `Box` is a case of "modern" elision. -/// - **Deprecated** -- this covers cases like `Ref`, where the lifetime -/// parameter to ref is completely elided. `Ref<'_, T>` would be the modern, -/// non-deprecated equivalent. -/// -/// Currently, the handling of lifetime elision is somewhat spread out -/// between HIR lowering and -- as described below -- the -/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating -/// an "elided" or "underscore" lifetime name. In the future, we probably want to move -/// everything into HIR lowering. -#[derive(Copy, Clone, Debug)] -pub enum AnonymousLifetimeMode { - /// For **Modern** cases, create a new anonymous region parameter - /// and reference that. - /// - /// For **Dyn Bound** cases, pass responsibility to - /// `resolve_lifetime` code. - /// - /// For **Deprecated** cases, report an error. - CreateParameter, - - /// Give a hard error when either `&` or `'_` is written. Used to - /// rule out things like `where T: Foo<'_>`. Does not imply an - /// error on default object bounds (e.g., `Box`). - ReportError, - - /// Pass responsibility to `resolve_lifetime` code for all cases. - PassThrough, -} - impl<'a, 'hir> LoweringContext<'a, 'hir> { fn with_hir_id_owner( &mut self, @@ -688,26 +665,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } - fn with_anonymous_lifetime_mode( - &mut self, - anonymous_lifetime_mode: AnonymousLifetimeMode, - op: impl FnOnce(&mut Self) -> R, - ) -> R { - debug!( - "with_anonymous_lifetime_mode(anonymous_lifetime_mode={:?})", - anonymous_lifetime_mode, - ); - let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode; - self.anonymous_lifetime_mode = anonymous_lifetime_mode; - let result = op(self); - self.anonymous_lifetime_mode = old_anonymous_lifetime_mode; - debug!( - "with_anonymous_lifetime_mode: restoring anonymous_lifetime_mode={:?}", - old_anonymous_lifetime_mode - ); - result - } - /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { @@ -723,135 +680,60 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Ident::new(ident.name, self.lower_span(ident.span)) } - /// Creates a new `hir::GenericParam` for every new lifetime and - /// type parameter encountered while evaluating `f`. Definitions - /// are created with the parent provided. If no `parent_id` is - /// provided, no definitions will be returned. - /// - /// Presuming that in-band lifetimes are enabled, then - /// `self.anonymous_lifetime_mode` will be updated to match the - /// parameter while `f` is running (and restored afterwards). - fn collect_in_band_defs( - &mut self, - parent_def_id: LocalDefId, - f: impl FnOnce(&mut Self) -> T, - ) -> (Vec<(Span, NodeId)>, T) { - let was_collecting = - std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, Some(parent_def_id)); - let len = self.lifetimes_to_define.len(); - - let res = f(self); - - let lifetimes_to_define = self.lifetimes_to_define.split_off(len); - self.is_collecting_anonymous_lifetimes = was_collecting; - (lifetimes_to_define, res) - } - /// Converts a lifetime into a new generic parameter. - fn fresh_lifetime_to_generic_param( + fn lifetime_res_to_generic_param( &mut self, - span: Span, + ident: Ident, node_id: NodeId, - ) -> hir::GenericParam<'hir> { + res: LifetimeRes, + ) -> Option> { + let (name, kind) = match res { + LifetimeRes::Param { .. } => { + (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit) + } + LifetimeRes::Fresh { param, .. } => { + (hir::ParamName::Fresh(param), hir::LifetimeParamKind::Elided) + } + LifetimeRes::Static | LifetimeRes::Error => return None, + res => panic!( + "Unexpected lifetime resolution {:?} for {:?} at {:?}", + res, ident, ident.span + ), + }; let hir_id = self.lower_node_id(node_id); - let def_id = self.resolver.local_def_id(node_id); - hir::GenericParam { + Some(hir::GenericParam { hir_id, - name: hir::ParamName::Fresh(def_id), + name, bounds: &[], - span: self.lower_span(span), + span: self.lower_span(ident.span), pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }, - } - } - - /// When we have either an elided or `'_` lifetime in an impl - /// header, we convert it to an in-band lifetime. - fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName { - let Some(parent_def_id) = self.is_collecting_anonymous_lifetimes else { panic!() }; - - let node_id = self.resolver.next_node_id(); - - // Add a definition for the in-band lifetime def. - let param_def_id = self.resolver.create_def( - parent_def_id, - node_id, - DefPathData::LifetimeNs(kw::UnderscoreLifetime), - ExpnId::root(), - span.with_parent(None), - ); - - let hir_name = ParamName::Fresh(param_def_id); - self.lifetimes_to_define.push((span, node_id)); - hir_name - } - - // Evaluates `f` with the lifetimes in `params` in-scope. - // This is used to track which lifetimes have already been defined, and - // which are new in-band lifetimes that need to have a definition created - // for them. - fn with_in_scope_lifetime_defs( - &mut self, - params: &[GenericParam], - f: impl FnOnce(&mut Self) -> T, - ) -> T { - let old_len = self.in_scope_lifetimes.len(); - let lt_def_names = params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(ParamName::Plain(param.ident.normalize_to_macros_2_0())) - } - _ => None, - }); - self.in_scope_lifetimes.extend(lt_def_names); - - let res = f(self); - - self.in_scope_lifetimes.truncate(old_len); - res + kind: hir::GenericParamKind::Lifetime { kind }, + }) } - /// Appends in-band lifetime defs and argument-position `impl - /// Trait` defs to the existing set of generics. - /// - /// Presuming that in-band lifetimes are enabled, then - /// `self.anonymous_lifetime_mode` will be updated to match the - /// parameter while `f` is running (and restored afterwards). - fn add_in_band_defs( + /// Creates a new `hir::GenericParam` for every new `Fresh` lifetime and + /// universal `impl Trait` type parameter encountered while evaluating `f`. + /// Definitions are created with the provided `parent_def_id`. + fn add_implicit_generics( &mut self, generics: &Generics, - parent_def_id: LocalDefId, - anonymous_lifetime_mode: AnonymousLifetimeMode, + parent_node_id: NodeId, f: impl FnOnce(&mut Self, &mut Vec>) -> T, ) -> (hir::Generics<'hir>, T) { - let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self - .collect_in_band_defs(parent_def_id, |this| { - this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| { - this.with_in_scope_lifetime_defs(&generics.params, |this| { - let mut impl_trait_defs = Vec::new(); - // Note: it is necessary to lower generics *before* calling `f`. - // When lowering `async fn`, there's a final step when lowering - // the return type that assumes that all in-scope lifetimes have - // already been added to either `in_scope_lifetimes` or - // `lifetimes_to_define`. If we swapped the order of these two, - // in-band-lifetimes introduced by generics or where-clauses - // wouldn't have been added yet. - let generics = this.lower_generics_mut( - generics, - ImplTraitContext::Universal( - &mut impl_trait_defs, - this.current_hir_id_owner, - ), - ); - let res = f(this, &mut impl_trait_defs); - (generics, impl_trait_defs, res) - }) - }) - }); + let mut impl_trait_defs = Vec::new(); + let mut lowered_generics = self.lower_generics_mut( + generics, + ImplTraitContext::Universal(&mut impl_trait_defs, self.current_hir_id_owner), + ); + let res = f(self, &mut impl_trait_defs); + let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); lowered_generics.params.extend( - lifetimes_to_define + extra_lifetimes .into_iter() - .map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id)) + .filter_map(|(ident, node_id, res)| { + self.lifetime_res_to_generic_param(ident, node_id, res) + }) .chain(impl_trait_defs), ); @@ -859,6 +741,45 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (lowered_generics, res) } + /// Setup lifetime capture for and impl-trait. + /// The captures will be added to `captures`. + fn while_capturing_lifetimes( + &mut self, + parent_def_id: LocalDefId, + captures: &mut FxHashMap, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let lifetime_stash = std::mem::replace( + &mut self.captured_lifetimes, + Some(LifetimeCaptureContext { + parent_def_id, + captures: std::mem::take(captures), + binders_to_ignore: Default::default(), + }), + ); + + let ret = f(self); + + let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap(); + *captures = ctxt.captures; + + ret + } + + /// 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 { + if let Some(ctxt) = &mut self.captured_lifetimes { + ctxt.binders_to_ignore.insert(binder); + } + let ret = f(self); + if let Some(ctxt) = &mut self.captured_lifetimes { + ctxt.binders_to_ignore.remove(&binder); + } + ret + } + fn with_dyn_type_scope(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T { let was_in_dyn_type = self.is_in_dyn_type; self.is_in_dyn_type = in_scope; @@ -1058,7 +979,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TypeBindingKind::Equality { term } } AssocConstraintKind::Bound { ref bounds } => { - let mut capturable_lifetimes; let mut parent_def_id = self.current_hir_id_owner; // Piggy-back on the `impl Trait` context to figure out the correct behavior. let (desugar_to_impl_trait, itctx) = match itctx { @@ -1091,13 +1011,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - capturable_lifetimes = FxHashSet::default(); - ( - true, - ImplTraitContext::TypeAliasesOpaqueTy { - capturable_lifetimes: &mut capturable_lifetimes, - }, - ) + (true, ImplTraitContext::TypeAliasesOpaqueTy) } // We are in the parameter position, but not within a dyn type: @@ -1258,26 +1172,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { - let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); - let lifetime = match *region { - Some(ref lt) => self.lower_lifetime(lt), - None => self.elided_ref_lifetime(span), - }; + let region = region.unwrap_or_else(|| { + let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) else { + panic!() + }; + debug_assert_eq!(start.plus(1), end); + let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); + Lifetime { + ident: Ident::new(kw::UnderscoreLifetime, span), + id: start, + } + }); + let lifetime = self.lower_lifetime(®ion); hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) } - TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| { - this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { - hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params( - &f.generic_params, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - ), - 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, |this| { + hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { + generic_params: this.lower_generic_params( + &f.generic_params, + ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + ), + 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) => { @@ -1342,28 +1261,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, ref bounds) => { let span = t.span; match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { fn_def_id, origin } => self - .lower_opaque_impl_trait( - span, - Some(fn_def_id), - origin, - def_node_id, - None, - |this| this.lower_param_bounds(bounds, itctx), - ), - ImplTraitContext::TypeAliasesOpaqueTy { ref capturable_lifetimes } => { - // Reset capturable lifetimes, any nested impl trait - // types will inherit lifetimes from this opaque type, - // so don't need to capture them again. - let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy { - capturable_lifetimes: &mut FxHashSet::default(), - }; + ImplTraitContext::ReturnPositionOpaqueTy { origin } => self + .lower_opaque_impl_trait(span, origin, def_node_id, |this| { + this.lower_param_bounds(bounds, itctx) + }), + ImplTraitContext::TypeAliasesOpaqueTy => { + let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; self.lower_opaque_impl_trait( span, - None, hir::OpaqueTyOrigin::TyAlias, def_node_id, - Some(capturable_lifetimes), |this| this.lower_param_bounds(bounds, nested_itctx), ) } @@ -1421,20 +1328,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } } + #[tracing::instrument(level = "debug", skip(self, lower_bounds))] fn lower_opaque_impl_trait( &mut self, span: Span, - fn_def_id: Option, origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, - capturable_lifetimes: Option<&FxHashSet>, lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>, ) -> hir::TyKind<'hir> { - debug!( - "lower_opaque_impl_trait(fn_def_id={:?}, opaque_ty_node_id={:?}, span={:?})", - fn_def_id, opaque_ty_node_id, span, - ); - // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop // desugaring that explicitly states that we don't want to track that. @@ -1444,48 +1345,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id); - let mut collected_lifetimes = Vec::new(); + let mut collected_lifetimes = FxHashMap::default(); self.with_hir_id_owner(opaque_ty_node_id, |lctx| { - let hir_bounds = lower_bounds(lctx); + let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias { + lower_bounds(lctx) + } else { + lctx.while_capturing_lifetimes( + opaque_ty_def_id, + &mut collected_lifetimes, + lower_bounds, + ) + }; + debug!(?collected_lifetimes); - collected_lifetimes = lifetimes_from_impl_trait_bounds( - opaque_ty_node_id, - &hir_bounds, - capturable_lifetimes, - ); + let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map( + |(_, &(span, p_id, p_name, _))| { + let hir_id = lctx.lower_node_id(p_id); + debug_assert_ne!(lctx.resolver.opt_local_def_id(p_id), None); - let lifetime_defs = - lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(|&(name, span)| { - let def_node_id = lctx.resolver.next_node_id(); - lctx.resolver.create_def( - opaque_ty_def_id, - def_node_id, - DefPathData::LifetimeNs(name.ident().name), - ExpnId::root(), - span.with_parent(None), - ); - let hir_id = lctx.lower_node_id(def_node_id); - - let (name, kind) = match name { - hir::LifetimeName::Underscore => ( - hir::ParamName::Plain(Ident::with_dummy_span(kw::UnderscoreLifetime)), - hir::LifetimeParamKind::Elided, - ), - hir::LifetimeName::Param(param_name) => { - (param_name, hir::LifetimeParamKind::Explicit) - } - _ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"), + let kind = if p_name.ident().name == kw::UnderscoreLifetime { + hir::LifetimeParamKind::Elided + } else { + hir::LifetimeParamKind::Explicit }; hir::GenericParam { hir_id, - name, + name: p_name, span, pure_wrt_drop: false, bounds: &[], kind: hir::GenericParamKind::Lifetime { kind }, } - })); + }, + )); debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); @@ -1503,10 +1396,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) }); - let lifetimes = - self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(name, span)| { - hir::GenericArg::Lifetime(hir::Lifetime { hir_id: self.next_id(), span, name }) - })); + let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map( + |(_, (span, _, p_name, res))| { + let id = self.resolver.next_node_id(); + let ident = Ident::new(p_name.ident().name, span); + let l = self.new_named_lifetime_with_res(id, span, ident, res); + hir::GenericArg::Lifetime(l) + }, + )); debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes); @@ -1565,7 +1462,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_fn_decl( &mut self, decl: &FnDecl, - mut in_band_ty_params: Option<(LocalDefId, &mut Vec>)>, + mut in_band_ty_params: Option<(NodeId, &mut Vec>)>, kind: FnDeclKind, make_ret_async: Option, ) -> &'hir hir::FnDecl<'hir> { @@ -1577,50 +1474,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { make_ret_async: {:?})", decl, in_band_ty_params, kind, make_ret_async, ); - let lt_mode = if make_ret_async.is_some() { - // 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. - AnonymousLifetimeMode::CreateParameter - } else { - self.anonymous_lifetime_mode - }; let c_variadic = decl.c_variadic(); - // Remember how many lifetimes were already around so that we can - // only look at the lifetime parameters introduced by the arguments. - let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| { - // Skip the `...` (`CVarArgs`) trailing arguments from the AST, - // as they are not explicit in HIR/Ty function signatures. - // (instead, the `c_variadic` flag is set to `true`) - let mut inputs = &decl.inputs[..]; - if c_variadic { - inputs = &inputs[..inputs.len() - 1]; + // Skip the `...` (`CVarArgs`) trailing arguments from the AST, + // as they are not explicit in HIR/Ty function signatures. + // (instead, the `c_variadic` flag is set to `true`) + let mut inputs = &decl.inputs[..]; + if c_variadic { + inputs = &inputs[..inputs.len() - 1]; + } + let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { + if let Some((_, ibty)) = &mut in_band_ty_params { + self.lower_ty_direct( + ¶m.ty, + ImplTraitContext::Universal(ibty, self.current_hir_id_owner), + ) + } else { + self.lower_ty_direct( + ¶m.ty, + ImplTraitContext::Disallowed(match kind { + FnDeclKind::Fn | FnDeclKind::Inherent => { + unreachable!("fn should allow in-band lifetimes") + } + FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, + FnDeclKind::Closure => ImplTraitPosition::ClosureParam, + FnDeclKind::Pointer => ImplTraitPosition::PointerParam, + FnDeclKind::Trait => ImplTraitPosition::TraitParam, + FnDeclKind::Impl => ImplTraitPosition::ImplParam, + }), + ) } - this.arena.alloc_from_iter(inputs.iter().map(|param| { - if let Some((_, ibty)) = &mut in_band_ty_params { - this.lower_ty_direct( - ¶m.ty, - ImplTraitContext::Universal(ibty, this.current_hir_id_owner), - ) - } else { - this.lower_ty_direct( - ¶m.ty, - ImplTraitContext::Disallowed(match kind { - FnDeclKind::Fn | FnDeclKind::Inherent => { - unreachable!("fn should allow in-band lifetimes") - } - FnDeclKind::ExternFn => ImplTraitPosition::ExternFnParam, - FnDeclKind::Closure => ImplTraitPosition::ClosureParam, - FnDeclKind::Pointer => ImplTraitPosition::PointerParam, - FnDeclKind::Trait => ImplTraitPosition::TraitParam, - FnDeclKind::Impl => ImplTraitPosition::ImplParam, - }), - ) - } - })) - }); + })); let output = if let Some(ret_id) = make_ret_async { self.lower_async_fn_ret_ty( @@ -1632,10 +1517,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match decl.output { FnRetTy::Ty(ref ty) => { let context = match in_band_ty_params { - Some((def_id, _)) if kind.impl_trait_return_allowed() => { + Some((node_id, _)) if kind.impl_trait_return_allowed() => { + let fn_def_id = self.resolver.local_def_id(node_id); ImplTraitContext::ReturnPositionOpaqueTy { - fn_def_id: def_id, - origin: hir::OpaqueTyOrigin::FnReturn(def_id), + origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), } } _ => ImplTraitContext::Disallowed(match kind { @@ -1696,25 +1581,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created // `elided_lt_replacement`: replacement for elided lifetimes in the return type + #[tracing::instrument(level = "debug", skip(self))] fn lower_async_fn_ret_ty( &mut self, output: &FnRetTy, - fn_def_id: LocalDefId, + fn_node_id: NodeId, opaque_ty_node_id: NodeId, ) -> hir::FnRetTy<'hir> { - debug!( - "lower_async_fn_ret_ty(\ - output={:?}, \ - fn_def_id={:?}, \ - opaque_ty_node_id={:?})", - output, fn_def_id, opaque_ty_node_id, - ); - let span = output.span(); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); let opaque_ty_def_id = self.resolver.local_def_id(opaque_ty_node_id); + let fn_def_id = self.resolver.local_def_id(fn_node_id); // When we create the opaque type for this async fn, it is going to have // to capture all the lifetimes involved in the signature (including in the @@ -1754,92 +1633,85 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // should be figured out using the ordinary elision rules, and // this desugaring achieves that. - debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes); - debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define); - // Calculate all the lifetimes that should be captured // by the opaque type. This should include all in-scope // lifetime parameters, including those defined in-band. - // - // `lifetime_params` is a vector of tuple (span, parameter name, lifetime name). - - // Input lifetime like `'a` or `'1`: - let mut lifetime_params: Vec<_> = self - .in_scope_lifetimes - .iter() - .cloned() - .map(|name| (name.ident().span, hir::LifetimeName::Param(name))) - .chain(self.lifetimes_to_define.iter().map(|&(span, node_id)| { - let def_id = self.resolver.local_def_id(node_id); - let name = hir::ParamName::Fresh(def_id); - (span, hir::LifetimeName::Param(name)) - })) - .collect(); + + let mut captures = FxHashMap::default(); + + let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id); + debug!(?extra_lifetime_params); + for (ident, outer_node_id, outer_res) in extra_lifetime_params { + let Ident { name, span } = ident; + let outer_def_id = self.resolver.local_def_id(outer_node_id); + let inner_node_id = self.resolver.next_node_id(); + + // Add a definition for the in scope lifetime def. + self.resolver.create_def( + opaque_ty_def_id, + inner_node_id, + DefPathData::LifetimeNs(name), + ExpnId::root(), + span.with_parent(None), + ); + + let (p_name, inner_res) = match outer_res { + // Input lifetime like `'a`: + LifetimeRes::Param { param, .. } => { + (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id }) + } + // Input lifetime like `'1`: + LifetimeRes::Fresh { param, .. } => ( + hir::ParamName::Fresh(outer_def_id), + LifetimeRes::Fresh { param, binder: fn_node_id }, + ), + LifetimeRes::Static | LifetimeRes::Error => continue, + res => { + panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span) + } + }; + + captures.insert(outer_def_id, (span, inner_node_id, p_name, inner_res)); + } + + debug!(?captures); self.with_hir_id_owner(opaque_ty_node_id, |this| { - let mut generic_params: Vec<_> = lifetime_params - .iter() - .map(|&(span, name)| { - // We can only get lifetime names from the outside. - let hir::LifetimeName::Param(hir_name) = name else { panic!() }; - - let node_id = this.resolver.next_node_id(); - - // Add a definition for the in-band lifetime def. - let def_id = this.resolver.create_def( - opaque_ty_def_id, - node_id, - DefPathData::LifetimeNs(hir_name.ident().name), - ExpnId::root(), - span.with_parent(None), - ); + let future_bound = + this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| { + // We have to be careful to get elision right here. The + // idea is that we create a lifetime parameter for each + // lifetime in the return type. So, given a return type + // like `async fn foo(..) -> &[&u32]`, we lower to `impl + // Future`. + // + // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and + // hence the elision takes place at the fn site. + this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span) + }); + debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound); + debug!("lower_async_fn_ret_ty: captures={:#?}", captures); - let (kind, name) = match hir_name { - ParamName::Plain(ident) => { - (hir::LifetimeParamKind::Explicit, hir::ParamName::Plain(ident)) - } - ParamName::Fresh(_) => { - (hir::LifetimeParamKind::Elided, hir::ParamName::Fresh(def_id)) - } - ParamName::Error => (hir::LifetimeParamKind::Error, hir::ParamName::Error), + let generic_params = + this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| { + let hir_id = this.lower_node_id(p_id); + debug_assert_ne!(this.resolver.opt_local_def_id(p_id), None); + + let kind = if p_name.ident().name == kw::UnderscoreLifetime { + hir::LifetimeParamKind::Elided + } else { + hir::LifetimeParamKind::Explicit }; hir::GenericParam { - hir_id: this.lower_node_id(node_id), - name, - bounds: &[], - span: this.lower_span(span), + hir_id, + name: p_name, + span, pure_wrt_drop: false, + bounds: &[], kind: hir::GenericParamKind::Lifetime { kind }, } - }) - .collect(); - - // We have to be careful to get elision right here. The - // idea is that we create a lifetime parameter for each - // lifetime in the return type. So, given a return type - // like `async fn foo(..) -> &[&u32]`, we lower to `impl - // Future`. - // - // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and - // hence the elision takes place at the fn site. - let (lifetimes_to_define, future_bound) = - this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| { - this.collect_in_band_defs(opaque_ty_def_id, |this| { - this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span) - }) - }); - debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound); - debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define); - - // Output lifetime like `'_`: - for (span, node_id) in lifetimes_to_define { - let param = this.fresh_lifetime_to_generic_param(span, node_id); - lifetime_params.push((span, hir::LifetimeName::Implicit)); - generic_params.push(param); - } - let generic_params = this.arena.alloc_from_iter(generic_params); - debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params); + })); debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); let opaque_ty_item = hir::OpaqueTy { @@ -1856,8 +1728,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span) }); - // As documented above on the variable - // `input_lifetimes_count`, we need to create the lifetime + // As documented above, we need to create the lifetime // arguments to our opaque type. Continuing with our example, // we're creating the type arguments for the return type: // @@ -1873,12 +1744,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // For the "output" lifetime parameters, we just want to // generate `'_`. let generic_args = - self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, name)| { - GenericArg::Lifetime(hir::Lifetime { - hir_id: self.next_id(), - span: self.lower_span(span), - name, - }) + self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| { + let id = self.resolver.next_node_id(); + let ident = Ident::new(p_name.ident().name, span); + let l = self.new_named_lifetime_with_res(id, span, ident, res); + hir::GenericArg::Lifetime(l) })); // Create the `Foo<...>` reference itself. Note that the `type @@ -1905,7 +1775,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `impl Future` opaque type that `async fn` implicitly // generates. let context = ImplTraitContext::ReturnPositionOpaqueTy { - fn_def_id, origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), }; self.lower_ty(ty, context) @@ -1948,35 +1817,106 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { let span = self.lower_span(l.ident.span); - match l.ident { - ident if ident.name == kw::StaticLifetime => { - self.new_named_lifetime(l.id, span, hir::LifetimeName::Static) - } - ident if ident.name == kw::UnderscoreLifetime => match self.anonymous_lifetime_mode { - AnonymousLifetimeMode::CreateParameter => { - let fresh_name = self.collect_fresh_anonymous_lifetime(span); - self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(fresh_name)) - } - - AnonymousLifetimeMode::PassThrough => { - self.new_named_lifetime(l.id, span, hir::LifetimeName::Underscore) - } - - AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span), - }, - ident => { - let param_name = ParamName::Plain(self.lower_ident(ident)); - self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name)) - } - } + let ident = self.lower_ident(l.ident); + let res = self + .resolver + .get_lifetime_res(l.id) + .unwrap_or_else(|| panic!("Missing resolution for lifetime {:?} at {:?}", l, span)); + self.new_named_lifetime_with_res(l.id, span, ident, res) } - fn new_named_lifetime( + #[tracing::instrument(level = "debug", skip(self))] + fn new_named_lifetime_with_res( &mut self, id: NodeId, span: Span, - name: hir::LifetimeName, + ident: Ident, + res: LifetimeRes, ) -> hir::Lifetime { + debug!(?self.captured_lifetimes); + let name = match res { + LifetimeRes::Param { param, binder } => { + debug_assert_ne!(ident.name, kw::UnderscoreLifetime); + let p_name = ParamName::Plain(ident); + if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = + &mut self.captured_lifetimes + && !binders_to_ignore.contains(&binder) + { + match captures.entry(param) { + Entry::Occupied(_) => {} + Entry::Vacant(v) => { + let p_id = self.resolver.next_node_id(); + self.resolver.create_def( + *parent_def_id, + p_id, + DefPathData::LifetimeNs(p_name.ident().name), + ExpnId::root(), + span.with_parent(None), + ); + + v.insert((span, p_id, p_name, res)); + } + } + } + hir::LifetimeName::Param(p_name) + } + LifetimeRes::Fresh { mut param, binder } => { + debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = + &mut self.captured_lifetimes + && !binders_to_ignore.contains(&binder) + { + match captures.entry(param) { + Entry::Occupied(o) => param = self.resolver.local_def_id(o.get().1), + Entry::Vacant(v) => { + let p_id = self.resolver.next_node_id(); + let p_def_id = self.resolver.create_def( + *parent_def_id, + p_id, + DefPathData::LifetimeNs(kw::UnderscoreLifetime), + ExpnId::root(), + span.with_parent(None), + ); + + let p_name = ParamName::Fresh(param); + v.insert((span, p_id, p_name, res)); + param = p_def_id; + } + } + } + let p_name = ParamName::Fresh(param); + hir::LifetimeName::Param(p_name) + } + LifetimeRes::Anonymous { binder, elided } => { + let l_name = if elided { + hir::LifetimeName::Implicit + } else { + hir::LifetimeName::Underscore + }; + if let Some(LifetimeCaptureContext { parent_def_id, captures, binders_to_ignore }) = + &mut self.captured_lifetimes + && !binders_to_ignore.contains(&binder) + { + let p_id = self.resolver.next_node_id(); + let p_def_id = self.resolver.create_def( + *parent_def_id, + p_id, + DefPathData::LifetimeNs(kw::UnderscoreLifetime), + ExpnId::root(), + span.with_parent(None), + ); + let p_name = ParamName::Fresh(p_def_id); + captures.insert(p_def_id, (span, p_id, p_name, res)); + hir::LifetimeName::Param(p_name) + } else { + l_name + } + } + LifetimeRes::Static => hir::LifetimeName::Static, + LifetimeRes::Error => hir::LifetimeName::Error, + res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span), + }; + debug!(?self.captured_lifetimes); hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } } @@ -2001,39 +1941,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { param: &GenericParam, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::GenericParam<'hir> { - let bounds: Vec<_> = self - .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { - this.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect() - }); + let bounds: Vec<_> = self.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect(); let (name, kind) = match param.kind { GenericParamKind::Lifetime => { - let was_collecting_in_band = self.is_collecting_anonymous_lifetimes; - self.is_collecting_anonymous_lifetimes = None; - - let lt = self - .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { - this.lower_lifetime(&Lifetime { id: param.id, ident: param.ident }) - }); - let param_name = match lt.name { - hir::LifetimeName::Param(param_name) => param_name, - hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { - hir::ParamName::Plain(lt.name.ident()) - } - hir::LifetimeName::ImplicitObjectLifetimeDefault => { - self.sess.diagnostic().span_bug( - param.ident.span, - "object-lifetime-default should not occur here", - ); - } - hir::LifetimeName::Static | hir::LifetimeName::Error => ParamName::Error, + let param_name = if param.ident.name == kw::StaticLifetime + || param.ident.name == kw::UnderscoreLifetime + { + ParamName::Error + } else { + let ident = self.lower_ident(param.ident); + ParamName::Plain(ident) }; - let kind = hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }; - self.is_collecting_anonymous_lifetimes = was_collecting_in_band; - (param_name, kind) } GenericParamKind::Type { ref default, .. } => { @@ -2047,10 +1969,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { - let ty = - self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| { - this.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) - }); + let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2087,6 +2006,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) } } + #[tracing::instrument(level = "debug", skip(self))] fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, @@ -2095,27 +2015,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bound_generic_params = self.lower_generic_params(&p.bound_generic_params, itctx.reborrow()); - let trait_ref = self.with_in_scope_lifetime_defs(&p.bound_generic_params, |this| { - // Any impl Trait types defined within this scope can capture - // lifetimes bound on this predicate. - let lt_def_names = p.bound_generic_params.iter().filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some(hir::LifetimeName::Param( - ParamName::Plain(param.ident.normalize_to_macros_2_0()), - )), - _ => None, - }); - if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx { - capturable_lifetimes.extend(lt_def_names.clone()); - } - - let res = this.lower_trait_ref(&p.trait_ref, itctx.reborrow()); - - if let ImplTraitContext::TypeAliasesOpaqueTy { ref mut capturable_lifetimes } = itctx { - for param in lt_def_names { - capturable_lifetimes.remove(¶m); - } - } - res + let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| { + this.lower_trait_ref(&p.trait_ref, itctx.reborrow()) }); hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } @@ -2378,98 +2279,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Ty { hir_id, kind, span: self.lower_span(span) } } - /// Invoked to create the lifetime argument for a type `&T` - /// with no explicit lifetime. - fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime { - match self.anonymous_lifetime_mode { - // Intercept when we are in an impl header or async fn and introduce an in-band - // lifetime. - // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh - // `'f`. - AnonymousLifetimeMode::CreateParameter => { - let fresh_name = self.collect_fresh_anonymous_lifetime(span); - hir::Lifetime { - hir_id: self.next_id(), - span: self.lower_span(span), - name: hir::LifetimeName::Param(fresh_name), - } - } - - AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), - - AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), - } - } - - /// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime; - /// return an "error lifetime". - fn new_error_lifetime(&mut self, id: Option, span: Span) -> hir::Lifetime { - let id = id.unwrap_or_else(|| self.resolver.next_node_id()); - self.new_named_lifetime(id, span, hir::LifetimeName::Error) - } - - /// Invoked to create the lifetime argument(s) for a path like - /// `std::cell::Ref`; note that implicit lifetimes in these - /// sorts of cases are deprecated. This may therefore report a warning or an - /// error, depending on the mode. - fn elided_path_lifetimes<'s>( - &'s mut self, - span: Span, - count: usize, - ) -> impl Iterator + Captures<'a> + Captures<'s> + Captures<'hir> { - (0..count).map(move |_| self.elided_path_lifetime(span)) - } - - fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime { - match self.anonymous_lifetime_mode { - AnonymousLifetimeMode::CreateParameter => { - // We should have emitted E0726 when processing this path above - self.sess - .delay_span_bug(span, "expected 'implicit elided lifetime not allowed' error"); - let id = self.resolver.next_node_id(); - self.new_named_lifetime(id, span, hir::LifetimeName::Error) - } - // `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. - AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => { - self.new_implicit_lifetime(span) - } - } - } - /// Invoked to create the lifetime argument(s) for an elided trait object /// bound, like the bound in `Box`. This method is not invoked /// when the bound is written, even if it is written with `'_` like in /// `Box`. In those cases, `lower_lifetime` is invoked. fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime { - match self.anonymous_lifetime_mode { - // NB. We intentionally ignore the create-parameter mode here. - // and instead "pass through" to resolve-lifetimes, which will apply - // the object-lifetime-defaulting rules. Elided object lifetime defaults - // do not act like other elided lifetimes. In other words, given this: - // - // impl Foo for Box - // - // we do not introduce a fresh `'_` to serve as the bound, but instead - // ultimately translate to the equivalent of: - // - // impl Foo for Box - // - // `resolve_lifetime` has the code to make that happen. - AnonymousLifetimeMode::CreateParameter => {} - - AnonymousLifetimeMode::ReportError => { - // ReportError applies to explicit use of `'_`. - } - - // This is the normal case. - AnonymousLifetimeMode::PassThrough => {} - } - let r = hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), @@ -2478,14 +2292,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!("elided_dyn_bound: r={:?}", r); r } - - fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { - hir::Lifetime { - hir_id: self.next_id(), - span: self.lower_span(span), - name: hir::LifetimeName::Implicit, - } - } } /// Helper struct for delayed construction of GenericArgs. @@ -2511,121 +2317,3 @@ impl<'hir> GenericArgsCtor<'hir> { this.arena.alloc(ga) } } - -#[tracing::instrument(level = "debug")] -fn lifetimes_from_impl_trait_bounds( - opaque_ty_id: NodeId, - bounds: hir::GenericBounds<'_>, - lifetimes_to_include: Option<&FxHashSet>, -) -> Vec<(hir::LifetimeName, Span)> { - // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that - // appear in the bounds, excluding lifetimes that are created within the bounds. - // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`. - struct ImplTraitLifetimeCollector<'r> { - collect_elided_lifetimes: bool, - currently_bound_lifetimes: Vec, - already_defined_lifetimes: FxHashSet, - lifetimes: Vec<(hir::LifetimeName, Span)>, - lifetimes_to_include: Option<&'r FxHashSet>, - } - - impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> { - fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) { - // Don't collect elided lifetimes used inside of `Fn()` syntax. - if parameters.parenthesized { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - intravisit::walk_generic_args(self, span, parameters); - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - intravisit::walk_generic_args(self, span, parameters); - } - } - - fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { - // Don't collect elided lifetimes used inside of `fn()` syntax. - if let hir::TyKind::BareFn(_) = t.kind { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - intravisit::walk_ty(self, t); - self.currently_bound_lifetimes.truncate(old_len); - - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - intravisit::walk_ty(self, t) - } - } - - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'v hir::PolyTraitRef<'v>, - modifier: hir::TraitBoundModifier, - ) { - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.currently_bound_lifetimes.truncate(old_len); - } - - fn visit_generic_param(&mut self, param: &'v hir::GenericParam<'v>) { - // Record the introduction of 'a in `for<'a> ...`. - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - // Introduce lifetimes one at a time so that we can handle - // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`. - let lt_name = hir::LifetimeName::Param(param.name); - self.currently_bound_lifetimes.push(lt_name); - } - - intravisit::walk_generic_param(self, param); - } - - fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { - let name = match lifetime.name { - hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { - if self.collect_elided_lifetimes { - // Use `'_` for both implicit and underscore lifetimes in - // `type Foo<'_> = impl SomeTrait<'_>;`. - hir::LifetimeName::Underscore - } else { - return; - } - } - hir::LifetimeName::Param(_) => lifetime.name, - - // Refers to some other lifetime that is "in - // scope" within the type. - hir::LifetimeName::ImplicitObjectLifetimeDefault => return, - - hir::LifetimeName::Error | hir::LifetimeName::Static => return, - }; - - if !self.currently_bound_lifetimes.contains(&name) - && !self.already_defined_lifetimes.contains(&name) - && self.lifetimes_to_include.map_or(true, |lifetimes| lifetimes.contains(&name)) - { - self.already_defined_lifetimes.insert(name); - - self.lifetimes.push((name, lifetime.span)); - } - } - } - - let mut lifetime_collector = ImplTraitLifetimeCollector { - collect_elided_lifetimes: true, - currently_bound_lifetimes: Vec::new(), - already_defined_lifetimes: FxHashSet::default(), - lifetimes: Vec::new(), - lifetimes_to_include, - }; - - for bound in bounds { - intravisit::walk_param_bound(&mut lifetime_collector, &bound); - } - - lifetime_collector.lifetimes -} diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 8bf4b8fcc3975..3c9399c1fdf80 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,15 +1,14 @@ use crate::ImplTraitPosition; -use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode}; -use super::{GenericArgsCtor, ParenthesizedGenericArgs}; +use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; +use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::{self as ast, *}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; -use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; -use rustc_span::symbol::Ident; +use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use smallvec::smallvec; @@ -47,30 +46,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => param_mode, }; - // Figure out if this is a type/trait segment, - // which may need lifetime elision performed. - let parent_def_id = |this: &mut Self, def_id: DefId| DefId { - krate: def_id.krate, - index: this.resolver.def_key(def_id).parent.expect("missing parent"), - }; - let type_def_id = match partial_res.base_res() { - Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => { - Some(parent_def_id(self, def_id)) - } - Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => { - Some(parent_def_id(self, def_id)) - } - Res::Def(DefKind::Struct, def_id) - | Res::Def(DefKind::Union, def_id) - | Res::Def(DefKind::Enum, def_id) - | Res::Def(DefKind::TyAlias, def_id) - | Res::Def(DefKind::Trait, def_id) - if i + 1 == proj_start => - { - Some(def_id) - } - _ => None, - }; let parenthesized_generic_args = match partial_res.base_res() { // `a::b::Trait(Args)` Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { @@ -90,13 +65,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => ParenthesizedGenericArgs::Err, }; - let num_lifetimes = type_def_id - .map_or(0, |def_id| self.resolver.item_generics_num_lifetimes(def_id)); self.lower_path_segment( p.span, segment, param_mode, - num_lifetimes, parenthesized_generic_args, itctx.reborrow(), ) @@ -143,7 +115,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p.span, segment, param_mode, - 0, ParenthesizedGenericArgs::Err, itctx.reborrow(), )); @@ -184,7 +155,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p.span, segment, param_mode, - 0, ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), ) @@ -209,14 +179,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path_span: Span, segment: &PathSegment, param_mode: ParamMode, - expected_lifetimes: usize, parenthesized_generic_args: ParenthesizedGenericArgs, itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PathSegment<'hir> { - debug!( - "path_span: {:?}, lower_path_segment(segment: {:?}, expected_lifetimes: {:?})", - path_span, segment, expected_lifetimes - ); + debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { @@ -224,7 +190,9 @@ 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(data), + ParenthesizedGenericArgs::Ok => { + self.lower_parenthesized_parameter_data(segment.id, 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"); @@ -274,33 +242,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let has_lifetimes = generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); - if !generic_args.parenthesized && !has_lifetimes && expected_lifetimes > 0 { - // Note: these spans are used for diagnostics when they can't be inferred. - // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let elided_lifetime_span = if generic_args.span.is_empty() { - // 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) - } else if generic_args.is_empty() { - // If there are brackets, but not generic arguments, then use the opening bracket - generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) - } else { - // Else use an empty span right after the opening bracket. - generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() - }; - generic_args.args = self - .elided_path_lifetimes(elided_lifetime_span, expected_lifetimes) - .map(GenericArg::Lifetime) - .chain(generic_args.args.into_iter()) - .collect(); - if let (ParamMode::Explicit, AnonymousLifetimeMode::CreateParameter) = - (param_mode, self.anonymous_lifetime_mode) - { - // Late resolver should have issued the error. - self.sess - .delay_span_bug(elided_lifetime_span, "implicit lifetime not allowed here"); - } + if !generic_args.parenthesized && !has_lifetimes { + self.maybe_insert_elided_lifetimes_in_path( + path_span, + segment.id, + segment.ident.span, + &mut generic_args, + ); } let res = self.expect_full_res(segment.id); @@ -323,6 +271,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } + fn maybe_insert_elided_lifetimes_in_path( + &mut self, + path_span: Span, + segment_id: NodeId, + segment_ident_span: Span, + generic_args: &mut GenericArgsCtor<'hir>, + ) { + let (start, end) = match self.resolver.get_lifetime_res(segment_id) { + Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end), + None => return, + Some(_) => panic!(), + }; + let expected_lifetimes = end.as_usize() - start.as_usize(); + debug!(expected_lifetimes); + + // Note: these spans are used for diagnostics when they can't be inferred. + // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label + let elided_lifetime_span = if generic_args.span.is_empty() { + // 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) + } else if generic_args.is_empty() { + // If there are brackets, but not generic arguments, then use the opening bracket + generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) + } else { + // Else use an empty span right after the opening bracket. + generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() + }; + + generic_args.args.insert_many( + 0, + (start.as_u32()..end.as_u32()).map(|i| { + let id = NodeId::from_u32(i); + let l = self.lower_lifetime(&Lifetime { + id, + ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span), + }); + GenericArg::Lifetime(l) + }), + ); + } + pub(crate) fn lower_angle_bracketed_parameter_data( &mut self, data: &AngleBracketedArgs, @@ -354,6 +345,7 @@ 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 @@ -361,7 +353,7 @@ 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_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| { + 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( diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b3de86662eb09..432883a11031b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -93,8 +93,6 @@ pub enum LifetimeName { Param(ParamName), /// User wrote nothing (e.g., the lifetime in `&u32`). - /// - /// The bool indicates whether the user should have written something. Implicit, /// Implicit lifetime in a context like `dyn Foo`. This is @@ -444,9 +442,6 @@ pub enum GenericBound<'hir> { Outlives(Lifetime), } -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); - impl GenericBound<'_> { pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { match self { @@ -3349,6 +3344,7 @@ mod size_asserts { 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); + rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48); rustc_data_structures::static_assert_size!(super::Item<'static>, 184); rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7635ad9bd87bf..b3197977d6fbe 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -14,13 +14,15 @@ use crate::{ResolutionError, Resolver, Segment, UseError}; use rustc_ast::ptr::P; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::*; -use rustc_ast_lowering::ResolverAstLowering; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::definitions::DefPathData; 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; @@ -195,7 +197,7 @@ enum LifetimeRibKind { Item, /// This rib declares generic parameters. - Generics { span: Span, kind: LifetimeBinderKind }, + Generics { parent: NodeId, span: Span, kind: LifetimeBinderKind }, /// For **Modern** cases, create a new anonymous region parameter /// and reference that. @@ -204,7 +206,7 @@ enum LifetimeRibKind { /// `resolve_lifetime` code. /// /// For **Deprecated** cases, report an error. - AnonymousCreateParameter, + AnonymousCreateParameter(NodeId), /// Give a hard error when either `&` or `'_` is written. Used to /// rule out things like `where T: Foo<'_>`. Does not imply an @@ -212,7 +214,7 @@ enum LifetimeRibKind { AnonymousReportError, /// Pass responsibility to `resolve_lifetime` code for all cases. - AnonymousPassThrough, + AnonymousPassThrough(NodeId), } #[derive(Copy, Clone, Debug)] @@ -242,7 +244,8 @@ impl LifetimeBinderKind { #[derive(Debug)] struct LifetimeRib { kind: LifetimeRibKind, - bindings: IdentMap<()>, + // We need to preserve insertion order for async fns. + bindings: FxIndexMap, } impl LifetimeRib { @@ -581,12 +584,19 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_generic_param_rib( &bare_fn.generic_params, NormalRibKind, - LifetimeRibKind::Generics { kind: LifetimeBinderKind::BareFnType, span }, + LifetimeRibKind::Generics { + parent: ty.id, + kind: LifetimeBinderKind::BareFnType, + span, + }, |this| { - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { - this.visit_generic_param_vec(&bare_fn.generic_params, false); - visit::walk_fn_decl(this, &bare_fn.decl); - }); + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(ty.id), + |this| { + this.visit_generic_param_vec(&bare_fn.generic_params, false); + visit::walk_fn_decl(this, &bare_fn.decl); + }, + ); }, ); self.diagnostic_metadata.current_trait_object = prev; @@ -604,7 +614,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_generic_param_rib( &tref.bound_generic_params, NormalRibKind, - LifetimeRibKind::Generics { kind: LifetimeBinderKind::PolyTrait, span }, + LifetimeRibKind::Generics { + parent: tref.trait_ref.ref_id, + kind: LifetimeBinderKind::PolyTrait, + span, + }, |this| { this.visit_generic_param_vec(&tref.bound_generic_params, false); this.smart_resolve_path( @@ -625,6 +639,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: foreign_item.id, kind: LifetimeBinderKind::Item, span: generics.span, }, @@ -638,6 +653,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: foreign_item.id, kind: LifetimeBinderKind::Function, span: generics.span, }, @@ -655,13 +671,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } } - fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) { + fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { let rib_kind = match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) | FnKind::Fn(_, _, sig, _, generics, None) => { - self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + self.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| { // We don't need to deal with patterns in parameters, because // they are not possible for foreign or bodiless functions. this.visit_fn_header(&sig.header); @@ -691,20 +707,50 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.visit_generics(generics); } - if async_node_id.is_some() { + 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, |this| { - // Add each argument to the rib. - this.resolve_params(&declaration.inputs) - }); + this.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter(fn_id), + |this| { + // Add each argument to the rib. + this.resolve_params(&declaration.inputs) + }, + ); - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { - visit::walk_fn_ret_ty(this, &declaration.output) - }); + // 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)), + ); + 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); + } + } + _ => {} + } + } + this.r.extra_lifetime_params_map.insert(async_node_id, extra_lifetime_params); + + this.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(async_node_id), + |this| visit::walk_fn_ret_ty(this, &declaration.output), + ); } else { - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| { // Add each argument to the rib. this.resolve_params(&declaration.inputs); @@ -716,13 +762,12 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // 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, - |this| match fn_kind { + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(fn_id), |this| { + match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), FnKind::Closure(_, body) => this.visit_expr(body), - }, - ); + } + }); debug!("(resolving function) leaving function"); this.in_func_body = previous_state; @@ -801,10 +846,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { if let Some(ref args) = path_segment.args { match &**args { GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, path_span, args), - GenericArgs::Parenthesized(..) => self - .with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, |this| { - visit::walk_generic_args(this, path_span, args) - }), + GenericArgs::Parenthesized(..) => self.with_lifetime_rib( + LifetimeRibKind::AnonymousPassThrough(path_segment.id), + |this| visit::walk_generic_args(this, path_span, args), + ), } } } @@ -830,7 +875,11 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { this.with_generic_param_rib( &bound_generic_params, NormalRibKind, - LifetimeRibKind::Generics { kind: LifetimeBinderKind::WhereBound, span }, + LifetimeRibKind::Generics { + parent: bounded_ty.id, + kind: LifetimeBinderKind::WhereBound, + span, + }, |this| { this.visit_generic_param_vec(&bound_generic_params, false); this.visit_ty(bounded_ty); @@ -1092,6 +1141,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let ident = lifetime.ident; if ident.name == kw::StaticLifetime { + self.record_lifetime_res(lifetime.id, LifetimeRes::Static); return; } @@ -1103,7 +1153,8 @@ 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(_) = rib.bindings.get_key_value(&normalized_ident) { + if let Some(&(_, region)) = rib.bindings.get(&normalized_ident) { + self.record_lifetime_res(lifetime.id, region); return; } @@ -1123,6 +1174,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } self.emit_undeclared_lifetime_error(lifetime, outer_res); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error); } #[tracing::instrument(level = "debug", skip(self))] @@ -1132,6 +1184,10 @@ 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); + return; + } LifetimeRibKind::AnonymousReportError => { let (msg, note) = if elided { ( @@ -1151,23 +1207,64 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .span_label(lifetime.ident.span, note) .emit(); + self.record_lifetime_res(lifetime.id, LifetimeRes::Error); + return; + } + LifetimeRibKind::AnonymousPassThrough(node_id) => { + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Anonymous { binder: node_id, elided }, + ); return; } - LifetimeRibKind::AnonymousCreateParameter - | LifetimeRibKind::AnonymousPassThrough - | LifetimeRibKind::Item => return, + LifetimeRibKind::Item => break, _ => {} } } + // This resolution is wrong, it passes the work to HIR lifetime resolution. + // We cannot use `LifetimeRes::Error` because we do not emit a diagnostic. + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Anonymous { binder: DUMMY_NODE_ID, elided }, + ); } #[tracing::instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); + self.record_lifetime_res( + anchor_id, + LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) }, + ); + let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; self.resolve_anonymous_lifetime(<, true); } + #[tracing::instrument(level = "debug", skip(self))] + fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, item_node_id: NodeId) { + 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 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, + )); + } + #[tracing::instrument(level = "debug", skip(self))] fn resolve_elided_lifetimes_in_path( &mut self, @@ -1231,7 +1328,7 @@ 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(_) => { error = true; break; } @@ -1241,13 +1338,29 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `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 + LifetimeRibKind::AnonymousPassThrough(..) | LifetimeRibKind::AnonymousReportError | LifetimeRibKind::Item => break, _ => {} } } + let res = if error { + LifetimeRes::Error + } else { + LifetimeRes::Anonymous { binder: segment_id, elided: true } + }; + + 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; } @@ -1296,6 +1409,16 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } + #[tracing::instrument(level = "debug", skip(self))] + fn record_lifetime_res(&mut self, id: NodeId, res: LifetimeRes) { + if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { + panic!( + "lifetime {:?} resolved multiple times ({:?} before, {:?} now)", + id, prev_res, res + ) + } + } + /// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved /// label and reports an error if the label is not found or is unreachable. fn resolve_label(&self, mut label: Ident) -> Option { @@ -1379,7 +1502,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_generic_param_rib( &generics.params, ItemRibKind(HasGenericParams::Yes), - LifetimeRibKind::Generics { kind: LifetimeBinderKind::Item, span: generics.span }, + LifetimeRibKind::Generics { + parent: item.id, + kind: LifetimeBinderKind::Item, + span: generics.span, + }, |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); this.with_self_rib( @@ -1446,6 +1573,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: item.id, kind: LifetimeBinderKind::Item, span: generics.span, }, @@ -1458,6 +1586,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: item.id, kind: LifetimeBinderKind::Function, span: generics.span, }, @@ -1487,6 +1616,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: item.id, kind: LifetimeBinderKind::Item, span: generics.span, }, @@ -1506,7 +1636,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_generic_param_rib( &generics.params, AssocItemRibKind, - LifetimeRibKind::Generics { span: generics.span, kind }, + LifetimeRibKind::Generics { + parent: item.id, + span: generics.span, + kind, + }, |this| { visit::walk_assoc_item(this, item, AssocCtxt::Trait) }, @@ -1571,6 +1705,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { + parent: item.id, kind: LifetimeBinderKind::Item, span: generics.span, }, @@ -1708,7 +1843,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { GenericParamKind::Type { .. } => (&mut function_type_rib, DefKind::TyParam), GenericParamKind::Const { .. } => (&mut function_value_rib, DefKind::ConstParam), GenericParamKind::Lifetime => { - function_lifetime_rib.bindings.insert(ident, ()); + let LifetimeRibKind::Generics { parent, .. } = lifetime_kind else { panic!() }; + let res = LifetimeRes::Param { param: def_id, binder: parent }; + self.record_lifetime_res(param.id, res); + function_lifetime_rib.bindings.insert(ident, (param.id, res)); continue; } }; @@ -1849,10 +1987,10 @@ 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, kind: LifetimeBinderKind::ImplBlock }, |this| { + self.with_generic_param_rib(&generics.params, ItemRibKind(HasGenericParams::Yes), LifetimeRibKind::Generics { span: generics.span, parent: 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, |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(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id); @@ -1876,7 +2014,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.visit_generics(generics); // Resolve the items within the impl. - this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough, + this.with_lifetime_rib(LifetimeRibKind::AnonymousPassThrough(item_id), |this| { this.with_current_self_type(self_type, |this| { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { @@ -1921,7 +2059,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_generic_param_rib( &generics.params, AssocItemRibKind, - LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Function }, + LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Function }, |this| { // If this is a trait impl, ensure the method // exists in trait @@ -1950,7 +2088,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_generic_param_rib( &generics.params, AssocItemRibKind, - LifetimeRibKind::Generics { span: generics.span, kind: LifetimeBinderKind::Item }, + LifetimeRibKind::Generics { parent: item.id, span: generics.span, kind: LifetimeBinderKind::Item }, |this| { // If this is a trait impl, ensure the type // exists in trait @@ -2655,9 +2793,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if !matches!(source, PathSource::TraitItem(..)) { // Avoid recording definition of `A::B` in `::B::C`. self.r.record_partial_res(id, partial_res); + self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize); } - self.resolve_elided_lifetimes_in_path(id, partial_res, path, source, finalize); partial_res } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d77cc917e2f9a..69f69d5f56686 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1824,7 +1824,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { for rib in self.lifetime_ribs.iter().rev() { match rib.kind { - LifetimeRibKind::Generics { span, kind } => { + LifetimeRibKind::Generics { parent: _, span, kind } => { if !span.can_be_used_for_suggestions() && suggest_note { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4dfb7aef86f5a..8df2ae5c33ba0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -29,7 +29,7 @@ use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID}; use rustc_ast::{AngleBracketedArg, Crate, Expr, ExprKind, GenericArg, GenericArgs, LitKind, Path}; -use rustc_ast_lowering::ResolverAstLowering; +use rustc_ast_lowering::{LifetimeRes, ResolverAstLowering}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; @@ -901,6 +901,10 @@ pub struct Resolver<'a> { import_res_map: NodeMap>>, /// Resolutions for labels (node IDs of their corresponding blocks or loops). label_res_map: NodeMap, + /// Resolutions for lifetimes. + lifetimes_res_map: NodeMap, + /// Lifetime parameters that lowering will have to introduce. + extra_lifetime_params_map: NodeMap>, /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap, @@ -1153,6 +1157,14 @@ impl ResolverAstLowering for Resolver<'_> { self.label_res_map.get(&id).cloned() } + fn get_lifetime_res(&self, id: NodeId) -> Option { + self.lifetimes_res_map.get(&id).copied() + } + + fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> { + self.extra_lifetime_params_map.remove(&id).unwrap_or_default() + } + fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { StableHashingContext::new(self.session, &self.definitions, self.crate_loader.cstore()) } @@ -1301,6 +1313,8 @@ impl<'a> Resolver<'a> { partial_res_map: Default::default(), import_res_map: Default::default(), label_res_map: Default::default(), + lifetimes_res_map: Default::default(), + extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), reexport_map: FxHashMap::default(), trait_map: NodeMap::default(), diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index 448d7ec287395..1c3d166a1af11 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -46,6 +46,7 @@ where fn create_doc() -> impl Document = DocCursorImpl<'_>> { //~^ ERROR: missing lifetime specifier + //~| 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 c5f59a24057d2..08efc82c88658 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -10,6 +10,18 @@ help: consider using the `'static` lifetime LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ~~~~~~~ -error: aborting due to previous error +error[E0106]: missing lifetime specifier + --> $DIR/issue-70304.rs:47:61 + | +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<'static>> { + | ~~~~~~~ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-trait/issues/issue-86800.rs b/src/test/ui/impl-trait/issues/issue-86800.rs index e8cef42f208ca..19edeaffc496f 100644 --- a/src/test/ui/impl-trait/issues/issue-86800.rs +++ b/src/test/ui/impl-trait/issues/issue-86800.rs @@ -27,16 +27,16 @@ type TransactionFuture<'__, O> = impl '__ + Future fn execute_transaction_fut<'f, F, O>( f: F, -) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture +) -> impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> where - F: FnOnce(&mut dyn Transaction) -> TransactionFuture + 'f + F: FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> + 'f { f } impl Context { async fn do_transaction( - &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture + &self, f: impl FnOnce(&mut dyn Transaction) -> TransactionFuture<'_, O> ) -> TransactionResult { let mut conn = Connection {};