diff options
Diffstat (limited to 'compiler/rustc_ast_lowering/src')
| -rw-r--r-- | compiler/rustc_ast_lowering/src/expr.rs | 40 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/index.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/item.rs | 369 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/lib.rs | 1253 | ||||
| -rw-r--r-- | compiler/rustc_ast_lowering/src/path.rs | 126 |
5 files changed, 734 insertions, 1073 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9442e0f1a1f..5c3e3be2116 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), )); @@ -222,6 +221,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let e = e.as_ref().map(|x| self.lower_expr(x)); hir::ExprKind::Ret(e) } + ExprKind::Yeet(ref sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()), ExprKind::InlineAsm(ref asm) => { hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm)) } @@ -1544,6 +1544,44 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + /// Desugar `ExprKind::Yeet` from: `do yeet <expr>` into: + /// ```rust + /// // If there is an enclosing `try {...}`: + /// break 'catch_target FromResidual::from_residual(Yeet(residual)), + /// // Otherwise: + /// return FromResidual::from_residual(Yeet(residual)), + /// ``` + /// But to simplify this, there's a `from_yeet` lang item function which + /// handles the combined `FromResidual::from_residual(Yeet(residual))`. + fn lower_expr_yeet(&mut self, span: Span, sub_expr: Option<&Expr>) -> hir::ExprKind<'hir> { + // The expression (if present) or `()` otherwise. + let (yeeted_span, yeeted_expr) = if let Some(sub_expr) = sub_expr { + (sub_expr.span, self.lower_expr(sub_expr)) + } else { + (self.mark_span_with_reason(DesugaringKind::YeetExpr, span, None), self.expr_unit(span)) + }; + + let unstable_span = self.mark_span_with_reason( + DesugaringKind::YeetExpr, + span, + self.allow_try_trait.clone(), + ); + + let from_yeet_expr = self.wrap_in_try_constructor( + hir::LangItem::TryTraitFromYeet, + unstable_span, + yeeted_expr, + yeeted_span, + ); + + if let Some(catch_node) = self.catch_scope { + let target_id = Ok(self.lower_node_id(catch_node)); + hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr)) + } else { + hir::ExprKind::Ret(Some(from_yeet_expr)) + } + } + // ========================================================================= // Helper methods for building HIR. // ========================================================================= diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 5eab21bf79a..c506360aa8a 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| { @@ -290,18 +295,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime)); } - fn visit_vis(&mut self, visibility: &'hir Visibility<'hir>) { - match visibility.node { - VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { hir_id, .. } => { - self.insert(visibility.span, hir_id, Node::Visibility(visibility)); - self.with_parent(hir_id, |this| { - intravisit::walk_vis(this, visibility); - }); - } - } - } - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { self.insert(v.span, v.id, Node::Variant(v)); self.with_parent(v.id, |this| { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a8bd8c92a41..5a95e5b084a 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; @@ -14,7 +14,7 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_index::vec::{Idx, IndexVec}; use rustc_session::utils::NtToTokenstream; use rustc_session::Session; -use rustc_span::source_map::{respan, DesugaringKind}; +use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; @@ -81,14 +81,11 @@ 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(), - allow_try_trait: Some([sym::try_trait_v2][..].into()), + captured_lifetimes: None, + allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].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(); } _ => {} }; @@ -230,15 +209,15 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let mut ident = i.ident; - let mut vis = self.lower_visibility(&i.vis); + let vis_span = self.lower_span(i.vis.span); let hir_id = self.lower_node_id(i.id); let attrs = self.lower_attrs(hir_id, &i.attrs); - let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind); + let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { def_id: hir_id.expect_owner(), ident: self.lower_ident(ident), kind, - vis, + vis_span, span: self.lower_span(i.span), }; self.arena.alloc(item) @@ -251,7 +230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: hir::HirId, ident: &mut Ident, attrs: Option<&'hir [Attribute]>, - vis: &mut hir::Visibility<'hir>, + vis_span: Span, i: &ItemKind, ) -> hir::ItemKind<'hir> { match *i { @@ -260,7 +239,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Start with an empty prefix. let prefix = Path { segments: vec![], span: use_tree.span, tokens: None }; - self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) + self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } ItemKind::Static(ref t, m, ref e) => { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); @@ -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,16 @@ 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, idpb| { let ret_id = asyncness.opt_return_id(); this.lower_fn_decl( &decl, - Some((fn_def_id, idty)), + Some((id, idty, idpb)), FnDeclKind::Fn, ret_id, ) - }, - ); + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(header), @@ -339,12 +313,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 +388,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 +401,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; @@ -454,7 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Positive => ImplPolarity::Positive, ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)), }; - hir::ItemKind::Impl(hir::Impl { + hir::ItemKind::Impl(self.arena.alloc(hir::Impl { unsafety: self.lower_unsafety(unsafety), polarity, defaultness, @@ -464,7 +425,7 @@ impl<'hir> LoweringContext<'_, 'hir> { of_trait: trait_ref, self_ty: lowered_ty, items: new_impl_items, - }) + })) } ItemKind::Trait(box Trait { is_auto, @@ -527,12 +488,11 @@ impl<'hir> LoweringContext<'_, 'hir> { tree: &UseTree, prefix: &Path, id: NodeId, - vis: &mut hir::Visibility<'hir>, + vis_span: Span, ident: &mut Ident, attrs: Option<&'hir [Attribute]>, ) -> hir::ItemKind<'hir> { debug!("lower_use_tree(tree={:?})", tree); - debug!("lower_use_tree: vis = {:?}", vis); let path = &tree.prefix; let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect(); @@ -586,7 +546,6 @@ impl<'hir> LoweringContext<'_, 'hir> { let res = this.lower_res(res); let path = this.lower_path_extra(res, &path, ParamMode::Explicit); let kind = hir::ItemKind::Use(path, hir::UseKind::Single); - let vis = this.rebuild_vis(&vis); if let Some(attrs) = attrs { this.attrs.insert(hir::ItemLocalId::new(0), attrs); } @@ -595,7 +554,7 @@ impl<'hir> LoweringContext<'_, 'hir> { def_id: new_id, ident: this.lower_ident(ident), kind, - vis, + vis_span, span: this.lower_span(span), }; hir::OwnerNode::Item(this.arena.alloc(item)) @@ -657,11 +616,10 @@ impl<'hir> LoweringContext<'_, 'hir> { // own its own names, we have to adjust the owner before // lowering the rest of the import. self.with_hir_id_owner(id, |this| { - let mut vis = this.rebuild_vis(&vis); let mut ident = *ident; let kind = - this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs); + this.lower_use_tree(use_tree, &prefix, id, vis_span, &mut ident, attrs); if let Some(attrs) = attrs { this.attrs.insert(hir::ItemLocalId::new(0), attrs); } @@ -670,37 +628,13 @@ impl<'hir> LoweringContext<'_, 'hir> { def_id: new_hir_id, ident: this.lower_ident(ident), kind, - vis, + vis_span, span: this.lower_span(use_tree.span), }; hir::OwnerNode::Item(this.arena.alloc(item)) }); } - // Subtle and a bit hacky: we lower the privacy level - // of the list stem to "private" most of the time, but - // not for "restricted" paths. The key thing is that - // we don't want it to stay as `pub` (with no caveats) - // because that affects rustdoc and also the lints - // about `pub` items. But we can't *always* make it - // private -- particularly not for restricted paths -- - // because it contains node-ids that would then be - // unused, failing the check that HirIds are "densely - // assigned". - match vis.node { - hir::VisibilityKind::Public - | hir::VisibilityKind::Crate(_) - | hir::VisibilityKind::Inherited => { - *vis = respan( - self.lower_span(prefix.span.shrink_to_lo()), - hir::VisibilityKind::Inherited, - ); - } - hir::VisibilityKind::Restricted { .. } => { - // Do nothing here, as described in the comment on the match. - } - } - let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err); let res = self.lower_res(res); let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit); @@ -709,37 +643,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - /// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated - /// many times in the HIR tree; for each occurrence, we need to assign distinct - /// `NodeId`s. (See, e.g., #56128.) - fn rebuild_use_path(&mut self, path: &hir::Path<'hir>) -> &'hir hir::Path<'hir> { - debug!("rebuild_use_path(path = {:?})", path); - let segments = - self.arena.alloc_from_iter(path.segments.iter().map(|seg| hir::PathSegment { - ident: seg.ident, - hir_id: seg.hir_id.map(|_| self.next_id()), - res: seg.res, - args: None, - infer_args: seg.infer_args, - })); - self.arena.alloc(hir::Path { span: path.span, res: path.res, segments }) - } - - fn rebuild_vis(&mut self, vis: &hir::Visibility<'hir>) -> hir::Visibility<'hir> { - let vis_kind = match vis.node { - hir::VisibilityKind::Public => hir::VisibilityKind::Public, - hir::VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), - hir::VisibilityKind::Inherited => hir::VisibilityKind::Inherited, - hir::VisibilityKind::Restricted { ref path, hir_id: _ } => { - hir::VisibilityKind::Restricted { - path: self.rebuild_use_path(path), - hir_id: self.next_id(), - } - } - }; - respan(self.lower_span(vis.span), vis_kind) - } - fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = self.lower_node_id(i.id); let def_id = hir_id.expect_owner(); @@ -750,18 +653,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) } @@ -773,7 +672,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), }, - vis: self.lower_visibility(&i.vis), + vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), }; self.arena.alloc(item) @@ -851,7 +750,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(jseyfried): positional field hygiene. None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, - vis: self.lower_visibility(&f.vis), + vis_span: self.lower_span(f.vis.span), ty, } } @@ -868,13 +767,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 +778,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 +852,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 +868,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 +888,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) } }; @@ -1016,8 +903,8 @@ impl<'hir> LoweringContext<'_, 'hir> { def_id: hir_id.expect_owner(), ident: self.lower_ident(i.ident), generics, - vis: self.lower_visibility(&i.vis), kind, + vis_span: self.lower_span(i.vis.span), span: self.lower_span(i.span), }; self.arena.alloc(item) @@ -1044,28 +931,6 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - /// If an `explicit_owner` is given, this method allocates the `HirId` in - /// the address space of that item instead of the item currently being - /// lowered. This can happen during `lower_impl_item_ref()` where we need to - /// lower a `Visibility` value although we haven't lowered the owning - /// `ImplItem` in question yet. - fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility<'hir> { - let node = match v.kind { - VisibilityKind::Public => hir::VisibilityKind::Public, - VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), - VisibilityKind::Restricted { ref path, id } => { - debug!("lower_visibility: restricted path id = {:?}", id); - let lowered_id = self.lower_node_id(id); - hir::VisibilityKind::Restricted { - path: self.lower_path(id, path, ParamMode::Explicit), - hir_id: lowered_id, - } - } - VisibilityKind::Inherited => hir::VisibilityKind::Inherited, - }; - respan(self.lower_span(v.span), node) - } - fn lower_defaultness( &self, d: Defaultness, @@ -1363,17 +1228,14 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, sig: &FnSig, - fn_def_id: LocalDefId, + id: NodeId, kind: FnDeclKind, is_async: Option<NodeId>, - ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) { + ) -> (&'hir 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, idpb| { + this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1432,7 +1294,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_generics_mut( &mut self, generics: &Generics, - itctx: ImplTraitContext<'_, 'hir>, + mut itctx: ImplTraitContext<'_, 'hir>, ) -> GenericsCtor<'hir> { // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering @@ -1481,9 +1343,24 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + let mut predicates = SmallVec::new(); + predicates.extend(generics.params.iter().filter_map(|param| { + let bounds = self.lower_param_bounds(¶m.bounds, itctx.reborrow()); + self.lower_generic_bound_predicate(param.ident, param.id, ¶m.kind, bounds) + })); + predicates.extend( + generics + .where_clause + .predicates + .iter() + .map(|predicate| self.lower_where_predicate(predicate)), + ); + GenericsCtor { - params: self.lower_generic_params_mut(&generics.params, itctx).collect(), - where_clause: self.lower_where_clause(&generics.where_clause), + params: self.lower_generic_params_mut(&generics.params).collect(), + predicates, + has_where_clause: !generics.where_clause.predicates.is_empty(), + where_clause_span: self.lower_span(generics.where_clause.span), span: self.lower_span(generics.span), } } @@ -1492,20 +1369,75 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, itctx: ImplTraitContext<'_, 'hir>, - ) -> hir::Generics<'hir> { + ) -> &'hir hir::Generics<'hir> { let generics_ctor = self.lower_generics_mut(generics, itctx); generics_ctor.into_generics(self.arena) } - 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), + pub(super) fn lower_generic_bound_predicate( + &mut self, + ident: Ident, + id: NodeId, + kind: &GenericParamKind, + bounds: &'hir [hir::GenericBound<'hir>], + ) -> Option<hir::WherePredicate<'hir>> { + // Do not create a clause if we do not have anything inside it. + if bounds.is_empty() { + return None; + } + let ident = self.lower_ident(ident); + let param_span = ident.span; + let span = bounds + .iter() + .fold(Some(param_span.shrink_to_hi()), |span: Option<Span>, bound| { + let bound_span = bound.span(); + // We include bounds that come from a `#[derive(_)]` but point at the user's code, + // as we use this method to get a span appropriate for suggestions. + if !bound_span.can_be_used_for_suggestions() { + None + } else if let Some(span) = span { + Some(span.to(bound_span)) + } else { + Some(bound_span) + } + }) + .unwrap_or(param_span.shrink_to_hi()); + match kind { + GenericParamKind::Const { .. } => None, + GenericParamKind::Type { .. } => { + let def_id = self.resolver.local_def_id(id).to_def_id(); + let ty_path = self.arena.alloc(hir::Path { + span: param_span, + res: Res::Def(DefKind::TyParam, def_id), + segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]), + }); + let ty_id = self.next_id(); + let bounded_ty = + self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path)); + Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bounded_ty: self.arena.alloc(bounded_ty), + bounds, + span, + bound_generic_params: &[], + in_where_clause: false, + })) } - }) + GenericParamKind::Lifetime => { + let ident_span = self.lower_span(ident.span); + let ident = self.lower_ident(ident); + let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| { + panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span) + }); + let lt_id = self.resolver.next_node_id(); + let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res); + Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + lifetime, + span, + bounds, + in_where_clause: false, + })) + } + } } fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { @@ -1515,24 +1447,18 @@ 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), + 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), + in_where_clause: true, }), WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, @@ -1545,6 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), + in_where_clause: true, }), WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { @@ -1563,16 +1490,20 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Helper struct for delayed construction of Generics. pub(super) struct GenericsCtor<'hir> { pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>, - where_clause: hir::WhereClause<'hir>, + pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>, + has_where_clause: bool, + where_clause_span: Span, span: Span, } impl<'hir> GenericsCtor<'hir> { - pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> hir::Generics<'hir> { - hir::Generics { + pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> { + arena.alloc(hir::Generics { params: arena.alloc_from_iter(self.params), - where_clause: self.where_clause, + predicates: arena.alloc_from_iter(self.predicates), + has_where_clause: self.has_where_clause, + where_clause_span: self.where_clause_span, span: self.span, - } + }) } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9cb205074e7..d433775f85c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,12 +32,13 @@ #![feature(crate_visibility_modifier)] #![feature(box_patterns)] +#![feature(let_chains)] #![feature(let_else)] #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] -use rustc_ast::token::{self, Token}; +use rustc_ast::token::{Delimiter, Token}; use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; use rustc_ast::visit; use rustc_ast::{self as ast, *}; @@ -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; @@ -61,7 +61,7 @@ use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::hygiene::{ExpnId, MacroKind}; -use rustc_span::source_map::{respan, DesugaringKind}; +use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -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<T>`). - 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<LocalDefId>, - - /// 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<ParamName>, + /// Used to handle lifetimes appearing in impl-traits. + captured_lifetimes: Option<LifetimeCaptureContext>, current_hir_id_owner: LocalDefId, item_local_id_counter: hir::ItemLocalId, @@ -157,6 +138,68 @@ struct LoweringContext<'a, 'hir: 'a> { allow_into_future: Option<Lrc<[Symbol]>>, } +/// 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<NodeId>, +} + 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<NodeId>; + /// Obtains resolution for a lifetime with the given `NodeId`. + fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>; + + /// 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; @@ -210,36 +259,18 @@ enum ImplTraitContext<'b, 'a> { /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`. /// /// Newly generated parameters should be inserted into the given `Vec`. - Universal(&'b mut Vec<hir::GenericParam<'a>>, LocalDefId), + Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId), /// Treat `impl Trait` as shorthand for a new opaque type. /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// 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<hir::LifetimeName>, - }, + TypeAliasesOpaqueTy, /// `impl Trait` is not accepted in this position. Disallowed(ImplTraitPosition), } @@ -272,13 +303,9 @@ impl<'a> ImplTraitContext<'_, 'a> { fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, '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 } - } + Universal(params, bounds, parent) => Universal(params, bounds, *parent), + 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<T>`, 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<T>`, and we sometimes just give hard errors in those cases -/// as well. -/// - for object bounds there is a difference: `Box<dyn Foo>` is not -/// the same as `Box<dyn Foo + '_>`. -/// -/// 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<dyn Foo>`, -/// there is an elided lifetime bound (`Box<dyn Foo + 'X>`). These -/// elided bounds follow special rules. Note that this only covers -/// cases where *nothing* is written; the `'_` in `Box<dyn Foo + -/// '_>` is a case of "modern" elision. -/// - **Deprecated** -- this covers cases like `Ref<T>`, 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<dyn Foo>`). - 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<R>( - &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,140 +680,114 @@ 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<T>( - &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<hir::GenericParam<'hir>> { + 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), - bounds: &[], - span: self.lower_span(span), + name, + span: self.lower_span(ident.span), pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }, - } + kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, + }) } - /// 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(); + /// 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<T>( + &mut self, + generics: &Generics, + parent_node_id: NodeId, + f: impl FnOnce( + &mut Self, + &mut Vec<hir::GenericParam<'hir>>, + &mut Vec<hir::WherePredicate<'hir>>, + ) -> T, + ) -> (&'hir hir::Generics<'hir>, T) { + let mut impl_trait_defs = Vec::new(); + let mut impl_trait_bounds = Vec::new(); + let mut lowered_generics = self.lower_generics_mut( + generics, + ImplTraitContext::Universal( + &mut impl_trait_defs, + &mut impl_trait_bounds, + self.current_hir_id_owner, + ), + ); + let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds); - // 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 extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); + lowered_generics.params.extend( + extra_lifetimes + .into_iter() + .filter_map(|(ident, node_id, res)| { + self.lifetime_res_to_generic_param(ident, node_id, res) + }) + .chain(impl_trait_defs), ); + lowered_generics.predicates.extend(impl_trait_bounds); - let hir_name = ParamName::Fresh(param_def_id); - self.lifetimes_to_define.push((span, node_id)); - hir_name + let lowered_generics = lowered_generics.into_generics(self.arena); + (lowered_generics, res) } - // 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<T>( + /// Setup lifetime capture for and impl-trait. + /// The captures will be added to `captures`. + fn while_capturing_lifetimes<T>( &mut self, - params: &[GenericParam], + parent_def_id: LocalDefId, + captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>, 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); + 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(), + }), + ); - self.in_scope_lifetimes.truncate(old_len); - res - } + let ret = f(self); - /// 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<T>( - &mut self, - generics: &Generics, - parent_def_id: LocalDefId, - anonymous_lifetime_mode: AnonymousLifetimeMode, - f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> 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 ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap(); + *captures = ctxt.captures; - lowered_generics.params.extend( - lifetimes_to_define - .into_iter() - .map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id)) - .chain(impl_trait_defs), - ); + ret + } - let lowered_generics = lowered_generics.into_generics(self.arena); - (lowered_generics, res) + /// Register a binder to be ignored for lifetime capture. + #[tracing::instrument(level = "debug", skip(self, f))] + #[inline] + fn with_lifetime_binder<T>(&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<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T { @@ -965,7 +896,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match tokens.into_trees().next() { Some(TokenTree::Token(token)) => token, Some(TokenTree::Delimited(_, delim, tokens)) => { - if delim != token::NoDelim { + if delim != Delimiter::Invisible { sess.diagnostic().delay_span_bug( span, "unexpected delimiter in key-value attribute's value", @@ -1058,7 +989,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 { @@ -1079,7 +1009,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator<Item = impl Debug>) - ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => { + ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => { parent_def_id = parent; (true, itctx) } @@ -1091,13 +1021,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 +1182,28 @@ 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), + 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,38 +1268,34 @@ 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), ) } - ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => { + ImplTraitContext::Universal( + in_band_ty_params, + in_band_ty_bounds, + parent_def_id, + ) => { // Add a definition for the in-band `Param`. let def_id = self.resolver.local_def_id(def_node_id); let hir_bounds = self.lower_param_bounds( bounds, - ImplTraitContext::Universal(in_band_ty_params, parent_def_id), + ImplTraitContext::Universal( + in_band_ty_params, + in_band_ty_bounds, + parent_def_id, + ), ); // Set the name to `impl Bound1 + Bound2`. let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); @@ -1381,10 +1303,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id: self.lower_node_id(def_node_id), name: ParamName::Plain(self.lower_ident(ident)), pure_wrt_drop: false, - bounds: hir_bounds, span: self.lower_span(span), kind: hir::GenericParamKind::Type { default: None, synthetic: true }, + colon_span: None, }); + if let Some(preds) = self.lower_generic_bound_predicate( + ident, + def_node_id, + &GenericParamKind::Type { default: None }, + hir_bounds, + ) { + in_band_ty_bounds.push(preds) + } hir::TyKind::Path(hir::QPath::Resolved( None, @@ -1421,20 +1351,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<LocalDefId>, origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, - capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>, 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,57 +1368,51 @@ 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 }, + colon_span: None, } - })); + }, + )); debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); let opaque_ty_item = hir::OpaqueTy { - generics: hir::Generics { + generics: self.arena.alloc(hir::Generics { params: lifetime_defs, - where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) }, + predicates: &[], + has_where_clause: false, + where_clause_span: lctx.lower_span(span), span: lctx.lower_span(span), - }, + }), bounds: hir_bounds, origin, }; @@ -1503,10 +1421,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); @@ -1530,7 +1452,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { def_id: opaque_ty_id, ident: Ident::empty(), kind: opaque_ty_item_kind, - vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited), + vis_span: self.lower_span(span.shrink_to_lo()), span: self.lower_span(opaque_ty_span), }; hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) @@ -1565,7 +1487,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_fn_decl( &mut self, decl: &FnDecl, - mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>, + mut in_band_ty_params: Option<( + NodeId, + &mut Vec<hir::GenericParam<'hir>>, + &mut Vec<hir::WherePredicate<'hir>>, + )>, kind: FnDeclKind, make_ret_async: Option<NodeId>, ) -> &'hir hir::FnDecl<'hir> { @@ -1577,50 +1503,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, ibpb)) = &mut in_band_ty_params { + self.lower_ty_direct( + ¶m.ty, + ImplTraitContext::Universal(ibty, ibpb, 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 +1546,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 +1610,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,100 +1662,95 @@ 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<Output = &'1 [ &'2 u32 ]>`. + // + // 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, kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, } - }) - .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<Output = &'1 [ &'2 u32 ]>`. - // - // 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 { - generics: hir::Generics { + generics: this.arena.alloc(hir::Generics { params: generic_params, - where_clause: hir::WhereClause { predicates: &[], span: this.lower_span(span) }, + predicates: &[], + has_where_clause: false, + where_clause_span: this.lower_span(span), span: this.lower_span(span), - }, + }), bounds: arena_vec![this; future_bound], origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), }; @@ -1856,8 +1759,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 +1775,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 +1806,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,92 +1848,134 @@ 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 } } fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], - mut itctx: ImplTraitContext<'s, 'hir>, ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> { - params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow())) + params.iter().map(move |param| self.lower_generic_param(param)) } - fn lower_generic_params( - &mut self, - params: &[GenericParam], - itctx: ImplTraitContext<'_, 'hir>, - ) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx)) + fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] { + self.arena.alloc_from_iter(self.lower_generic_params_mut(params)) } - fn lower_generic_param( - &mut self, - 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() - }); - + fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> { 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 +1989,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)), @@ -2070,8 +2009,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { name, span: self.lower_span(param.span()), pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle), - bounds: self.arena.alloc_from_iter(bounds), kind, + colon_span: param.colon_span.map(|s| self.lower_span(s)), } } @@ -2087,35 +2026,16 @@ 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, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'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()); + let bound_generic_params = self.lower_generic_params(&p.bound_generic_params); - 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 +2298,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<NodeId>, 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<T>`; 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<Item = hir::Lifetime> + 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<dyn Debug>`. This method is not invoked /// when the bound is written, even if it is written with `'_` like in /// `Box<dyn Debug + '_>`. 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<dyn Debug> - // - // we do not introduce a fresh `'_` to serve as the bound, but instead - // ultimately translate to the equivalent of: - // - // impl Foo for Box<dyn Debug + 'static> - // - // `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 +2311,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 +2336,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<hir::LifetimeName>>, -) -> 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<hir::LifetimeName>, - already_defined_lifetimes: FxHashSet<hir::LifetimeName>, - lifetimes: Vec<(hir::LifetimeName, Span)>, - lifetimes_to_include: Option<&'r FxHashSet<hir::LifetimeName>>, - } - - 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 8bf4b8fcc39..3c9399c1fdf 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( |
