diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index adde518af0f41..df5ea7c3168ff 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -122,8 +122,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356) - let sig_id = if let Some(delegation_info) = - self.resolver.delegation_info(self.local_def_id(item_id)) + let sig_id = if let Some(delegation_info) = self.resolver.delegation_info(self.owner.def_id) { self.get_sig_id(delegation_info.resolution_node, span) } else { @@ -143,8 +142,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (param_count, c_variadic) = self.param_count(sig_id); - let mut generics = - self.uplift_delegation_generics(delegation, sig_id, item_id, is_method); + let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method); let body_id = self.lower_delegation_body( delegation, diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index afffc20adf4b3..c2c3bd740e3cf 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -231,11 +231,9 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, sig_id: DefId, - item_id: NodeId, is_method: bool, ) -> GenericsGenerationResults<'hir> { - let delegation_parent_kind = - self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))); + let delegation_parent_kind = self.tcx.def_kind(self.tcx.local_parent(self.owner.def_id)); let segments = &delegation.path.segments; let len = segments.len(); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 249f8e579eee9..5f236c5ce531d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -98,7 +98,7 @@ impl<'hir> ItemLowerer<'_, 'hir> { match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); + assert_eq!(self.resolver.owner_id(CRATE_NODE_ID), CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? @@ -445,7 +445,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(id), + parent: this.owner.def_id, in_assoc_ty: false, }, }, @@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => { let ident = self.lower_ident(*ident); let body = Box::new(self.lower_delim_args(body)); - let def_id = self.local_def_id(id); + let def_id = self.owner.def_id; let def_kind = self.tcx.def_kind(def_id); let DefKind::Macro(macro_kinds) = def_kind else { unreachable!( @@ -1282,7 +1282,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), + parent: this.owner.def_id, in_assoc_ty: true, }, }, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1ce4478c09e8b..2bd58be73c370 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -61,7 +61,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::hir::{self as mid_hir}; use rustc_middle::span_bug; -use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::{DelegationInfo, PerOwnerResolverData, ResolverAstLowering, TyCtxt}; use rustc_session::errors::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; @@ -126,6 +126,7 @@ struct LoweringContext<'a, 'hir> { is_in_dyn_type: bool, current_hir_id_owner: hir::OwnerId, + owner: &'a PerOwnerResolverData, item_local_id_counter: hir::ItemLocalId, trait_map: ItemLocalMap<&'hir [TraitCandidate<'hir>]>, @@ -168,6 +169,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tcx, resolver, current_disambiguator: Default::default(), + owner: &resolver.owners[&CRATE_NODE_ID], arena: tcx.hir_arena, // HirId handling. @@ -310,12 +312,8 @@ impl<'tcx> ResolverAstLowering<'tcx> { self.delegation_infos.get(&id) } - fn opt_local_def_id(&self, id: NodeId) -> Option { - self.node_id_to_def_id.get(&id).copied() - } - - fn local_def_id(&self, id: NodeId) -> LocalDefId { - self.opt_local_def_id(id).expect("must have def_id") + fn owner_id(&self, id: NodeId) -> LocalDefId { + self.owners[&id].def_id } fn lifetime_elision_allowed(&self, id: NodeId) -> bool { @@ -483,20 +481,20 @@ fn index_crate<'a, 'b>( } fn visit_item(&mut self, item: &'a ast::Item) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item); visit::walk_item(self, item) } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::AssocItem(item, ctxt); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::ForeignItem(item); visit::walk_item(self, item); @@ -662,12 +660,25 @@ impl<'hir> LoweringContext<'_, 'hir> { fn opt_local_def_id(&self, node: NodeId) -> Option { self.node_id_to_def_id .get(&node) - .or_else(|| self.resolver.node_id_to_def_id.get(&node)) + .or_else(|| self.owner.node_id_to_def_id.get(&node)) .copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) + self.opt_local_def_id(node).unwrap_or_else(|| { + self.resolver.owners.items().any(|(id, items)| { + items.node_id_to_def_id.items().any(|(node_id, def_id)| { + if *node_id == node { + panic!( + "{def_id:?} ({node_id}) was found in {:?} ({id})", + items.node_id_to_def_id.get(id), + ) + } + false + }) + }); + panic!("no entry for node id: `{node:?}`"); + }) } fn get_partial_res(&self, id: NodeId) -> Option { @@ -679,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. fn owner_id(&self, node: NodeId) -> hir::OwnerId { - hir::OwnerId { def_id: self.local_def_id(node) } + hir::OwnerId { def_id: self.resolver.owners[&node].def_id } } /// Freshen the `LoweringContext` and ready it to lower a nested item. @@ -704,6 +715,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .unwrap_or_else(|| PerParentDisambiguatorState::new(def_id)); let disambiguator = std::mem::replace(&mut self.current_disambiguator, new_disambig); + let current_ast_owner = std::mem::replace(&mut self.owner, &self.resolver.owners[&owner]); let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_define_opaque = std::mem::take(&mut self.define_opaque); @@ -739,6 +751,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let info = self.make_owner_info(item); self.current_disambiguator = disambiguator; + self.owner = current_ast_owner; self.attrs = current_attrs; self.bodies = current_bodies; self.define_opaque = current_define_opaque; @@ -1787,7 +1800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let output = match coro { Some(coro) => { - let fn_def_id = self.local_def_id(fn_node_id); + let fn_def_id = self.owner.def_id; self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind) } None => match &decl.output { @@ -1795,19 +1808,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = match kind { FnDeclKind::Fn | FnDeclKind::Inherent => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: None, }, }, FnDeclKind::Trait => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: Some(hir::RpitContext::Trait), }, }, FnDeclKind::Impl => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: Some(hir::RpitContext::TraitImpl), }, }, diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 779615f73039f..f585eb9053c2f 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -34,6 +34,11 @@ use crate::stable_hasher::{ pub struct UnordItems>(I); impl> UnordItems { + #[inline] + pub fn wrap(iter: I) -> Self { + Self(iter) + } + #[inline] pub fn map U>(self, f: F) -> UnordItems> { UnordItems(self.0.map(f)) @@ -62,6 +67,14 @@ impl> UnordItems { UnordItems(self.0.filter_map(f)) } + #[inline] + pub fn chain( + self, + other: UnordItems>, + ) -> UnordItems> { + UnordItems(self.0.chain(other.0)) + } + #[inline] pub fn max(self) -> Option where @@ -102,10 +115,10 @@ impl> UnordItems { #[inline] pub fn flat_map(self, f: F) -> UnordItems> where - U: IntoIterator, - F: Fn(T) -> U, + U: Iterator, + F: Fn(T) -> UnordItems, { - UnordItems(self.0.flat_map(f)) + UnordItems(self.0.flat_map(move |x| f(x).0)) } pub fn collect>>(self) -> C { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7f1b58dd1de08..d0bb23206daa2 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1180,6 +1180,13 @@ pub trait ResolverExpand { /// Mark the scope as having a compile error so that error for lookup in this scope /// should be suppressed fn mark_scope_with_compile_error(&mut self, parent_node: NodeId); + + /// Set a new owner and return the old one. Use only in the implementation + /// of `with_owner` and always call [Self::reset_owner] afterwards + fn set_owner(&mut self, id: NodeId) -> NodeId; + + /// Switch back to the original owner. + fn reset_owner(&mut self, id: NodeId); } pub trait LintStoreExpand { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 741c34e0304af..75e0173f19b75 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -8,9 +8,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, - DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, - HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, - PatKind, StmtKind, TyKind, token, + CRATE_NODE_ID, DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, + ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, + MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; use rustc_attr_parsing::parser::AllowExprMetavar; @@ -2474,11 +2474,22 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { }; } } + + fn with_owner(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + if id == DUMMY_NODE_ID { + f(self) + } else { + let old = self.cx.resolver.set_owner(id); + let val = f(self); + self.cx.resolver.reset_owner(old); + val + } + } } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_item(&mut self, node: Box) -> SmallVec<[Box; 1]> { - self.flat_map_node(node) + self.with_owner(node.id, |this| this.flat_map_node(node)) } fn flat_map_assoc_item( @@ -2486,22 +2497,22 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { node: Box, ctxt: AssocCtxt, ) -> SmallVec<[Box; 1]> { - match ctxt { - AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), + self.with_owner(node.id, |this| match ctxt { + AssocCtxt::Trait => this.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), AssocCtxt::Impl { of_trait: false, .. } => { - self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) + this.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) } AssocCtxt::Impl { of_trait: true, .. } => { - self.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag)) + this.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag)) } - } + }) } fn flat_map_foreign_item( &mut self, node: Box, ) -> SmallVec<[Box; 1]> { - self.flat_map_node(node) + self.with_owner(node.id, |this| this.flat_map_node(node)) } fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> { @@ -2572,7 +2583,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } fn visit_crate(&mut self, node: &mut ast::Crate) { - self.visit_node(node) + self.with_owner(CRATE_NODE_ID, |this| this.visit_node(node)) } fn visit_ty(&mut self, node: &mut ast::Ty) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f68526724135c..ecdca5ca58246 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -198,6 +198,21 @@ pub struct ResolverGlobalCtxt { pub stripped_cfg_items: Vec, } +#[derive(Debug)] +pub struct PerOwnerResolverData { + pub node_id_to_def_id: NodeMap, + /// The id of the owner + pub id: ast::NodeId, + /// The `DefId` of the owner, can't be found in `node_id_to_def_id`. + pub def_id: LocalDefId, +} + +impl PerOwnerResolverData { + pub fn new(id: ast::NodeId, def_id: LocalDefId) -> Self { + Self { node_id_to_def_id: Default::default(), id, def_id } + } +} + /// Resolutions that should only be used for lowering. /// This struct is meant to be consumed by lowering. #[derive(Debug)] @@ -215,7 +230,7 @@ pub struct ResolverAstLowering<'tcx> { pub next_node_id: ast::NodeId, - pub node_id_to_def_id: NodeMap, + pub owners: NodeMap, pub trait_map: NodeMap<&'tcx [hir::TraitCandidate<'tcx>]>, /// List functions and methods for which lifetime elision was successful. diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 527c618c7a264..c274ca48df622 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -295,7 +295,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( target, - self.resolver.node_id_to_def_id[&i.id], + self.resolver.owners[&i.id].def_id, &i.attrs, i.span, i.opt_generics(), @@ -309,7 +309,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { fn visit_variant(&mut self, variant: &'ast ast::Variant) { self.check_for_lang( Target::Variant, - self.resolver.node_id_to_def_id[&variant.id], + self.resolver.owners[&self.parent_item.unwrap().id].node_id_to_def_id[&variant.id], &variant.attrs, variant.span, None, @@ -346,13 +346,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { } }; - self.check_for_lang( - target, - self.resolver.node_id_to_def_id[&i.id], - &i.attrs, - i.span, - generics, - ); + self.check_for_lang(target, self.resolver.owners[&i.id].def_id, &i.attrs, i.span, generics); visit::walk_assoc_item(self, i, ctxt); } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 61da931df4d5d..54a50c2203361 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -743,12 +743,13 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } ast::UseTreeKind::Nested { ref items, .. } => { for &(ref tree, id) in items { - let feed = self.create_def(id, None, DefKind::Use, use_tree.span()); - self.build_reduced_graph_for_use_tree( - // This particular use tree - tree, id, &prefix, true, false, // The whole `use` item - item, vis, root_span, feed, - ); + self.with_owner(id, None, DefKind::Use, use_tree.span(), |this, feed| { + this.build_reduced_graph_for_use_tree( + // This particular use tree + tree, id, &prefix, true, false, // The whole `use` item + item, vis, root_span, feed, + ) + }); } // Empty groups `a::b::{}` are turned into synthetic `self` imports diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 8ab0087ae6158..3c4a7357d115c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -31,6 +31,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan}; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::LocalDefId; use rustc_session::lint::builtin::{ MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS, }; @@ -81,9 +82,8 @@ struct ExternCrateToLint { impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // We have information about whether `use` (import) items are actually // used now. If an import is not used at all, we signal a lint error. - fn check_import(&mut self, id: ast::NodeId) { + fn check_import(&mut self, id: ast::NodeId, def_id: LocalDefId) { let used = self.r.used_imports.contains(&id); - let def_id = self.r.local_def_id(id); if !used { if self.r.maybe_unused_trait_imports.contains(&def_id) { // Check later. @@ -102,7 +102,8 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { - if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { + let def_id = self.r.owner_id(id); + if self.r.effective_visibilities.is_exported(def_id) { self.check_import_as_underscore(use_tree, id); return; } @@ -112,7 +113,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { self.unused_import(self.base_id).add(id); } } else { - self.check_import(id); + self.check_import(id, def_id); } } @@ -210,9 +211,8 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { continue; } - let module = self - .r - .get_nearest_non_block_module(self.r.local_def_id(extern_crate.id).to_def_id()); + let module = + self.r.get_nearest_non_block_module(self.r.owner_id(extern_crate.id).to_def_id()); if module.no_implicit_prelude { // If the module has `no_implicit_prelude`, then we don't suggest // replacing the extern crate with a use, as it would not be @@ -494,7 +494,7 @@ impl Resolver<'_, '_> { None } else { let parent_module = visitor.r.get_nearest_non_block_module( - visitor.r.local_def_id(unused.use_tree_id).to_def_id(), + visitor.r.owner_id(unused.use_tree_id).to_def_id(), ); match module_to_string(parent_module) { Some(module) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b5f46052f03e3..6e86dc61a3791 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -9,9 +9,9 @@ use rustc_hir as hir; use rustc_hir::Target; use rustc_hir::def::DefKind; use rustc_hir::def::Namespace::{TypeNS, ValueNS}; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::span_bug; -use rustc_middle::ty::TyCtxtFeed; +use rustc_middle::ty::{PerOwnerResolverData, TyCtxtFeed}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -25,8 +25,15 @@ pub(crate) fn collect_definitions<'ra>( ) -> MacroRulesScopeRef<'ra> { let invocation_parent = resolver.invocation_parents[&parent_scope.expansion]; debug!("new fragment to visit with invocation_parent: {invocation_parent:?}"); + debug_assert_eq!(resolver.current_owner.id, DUMMY_NODE_ID); + resolver.current_owner = resolver.owners.remove(&invocation_parent.owner).unwrap(); let mut visitor = DefCollector { r: resolver, invocation_parent, parent_scope }; fragment.visit_with(&mut visitor); + let tables = mem::replace( + &mut visitor.r.current_owner, + PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), + ); + assert!(visitor.r.owners.insert(invocation_parent.owner, tables).is_none()); visitor.parent_scope.macro_rules } @@ -57,6 +64,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { def_kind, self.parent_scope.expansion.to_expn_id(), span.with_parent(None), + false, ) } @@ -66,6 +74,39 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.invocation_parent.parent_def = orig_parent_def; } + pub(super) fn with_owner)>( + &mut self, + owner: NodeId, + name: Option, + def_kind: DefKind, + span: Span, + f: F, + ) { + debug_assert_ne!(owner, DUMMY_NODE_ID); + debug_assert_ne!(owner, CRATE_NODE_ID); + // We only get here if the owner didn't exist yet. After the owner has been created, + // future invocations of `collect_definitions` will get the owner out of the `owners` + // table. + debug_assert!(!self.r.owners.contains_key(&owner)); + let parent_def = self.invocation_parent.parent_def; + let feed = self.r.create_def( + parent_def, + owner, + name, + def_kind, + self.parent_scope.expansion.to_expn_id(), + span.with_parent(None), + true, + ); + let tables = PerOwnerResolverData::new(owner, feed.key()); + let orig_owner = mem::replace(&mut self.r.current_owner, tables); + let orig_invoc_owner = mem::replace(&mut self.invocation_parent.owner, owner); + f(self, feed); + let tables = mem::replace(&mut self.r.current_owner, orig_owner); + assert!(self.r.owners.insert(owner, tables).is_none()); + assert_eq!(mem::replace(&mut self.invocation_parent.owner, orig_invoc_owner), owner); + } + fn with_impl_trait( &mut self, impl_trait_context: ImplTraitContext, @@ -172,9 +213,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(_) => { - let feed = self.create_def(i.id, None, DefKind::Use, i.span); - self.brg_visit_item(i, feed); - return; + return self.with_owner(i.id, None, DefKind::Use, i.span, |this, feed| { + this.brg_visit_item(i, feed); + }); } ItemKind::MacCall(..) => { self.visit_macro_invoc(i.id); @@ -183,15 +224,23 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::DelegationMac(..) => unreachable!(), }; - let feed = self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); - - if let Some(ext) = opt_syn_ext { - self.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); - } + self.with_owner( + i.id, + i.kind.ident().map(|ident| ident.name), + def_kind, + i.span, + |this, feed| { + if let Some(ext) = opt_syn_ext { + this.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); + } - self.with_parent(feed.def_id(), |this| { - this.with_impl_trait(ImplTraitContext::Existential, |this| this.brg_visit_item(i, feed)) - }); + this.with_parent(feed.def_id(), |this| { + this.with_impl_trait(ImplTraitContext::Existential, |this| { + this.brg_visit_item(i, feed) + }) + }); + }, + ); } fn visit_block(&mut self, block: &'a Block) { @@ -282,12 +331,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span); - - self.with_parent(def.def_id(), |this| { - this.build_reduced_graph_for_foreign_item(fi, ident, def); - visit::walk_item(this, fi) - }); + self.with_owner(fi.id, Some(ident.name), def_kind, fi.span, |this, def| { + this.with_parent(def.def_id(), |this| { + this.build_reduced_graph_for_foreign_item(fi, ident, def); + visit::walk_item(this, fi) + }); + }) } fn visit_variant(&mut self, v: &'a Variant) { @@ -366,8 +415,11 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let feed = self.create_def(i.id, Some(ident.name), def_kind, i.span); - self.with_parent(feed.def_id(), |this| this.brg_visit_assoc_item(i, ctxt, ident, ns, feed)); + self.with_owner(i.id, Some(ident.name), def_kind, i.span, |this, feed| { + this.with_parent(feed.def_id(), |this| { + this.brg_visit_assoc_item(i, ctxt, ident, ns, feed) + }); + }) } fn visit_pat(&mut self, pat: &'a Pat) { @@ -564,6 +616,13 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } else { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. + + // We always have an invocation parent (set in `collect_definitions`) + // of at least the crate root, even for visiting the crate root, + // which would then remove the crate root from the tables + // list twice and try to insert it twice afterwards. + debug_assert_eq!(self.r.current_owner.id, CRATE_NODE_ID); + visit::walk_list!(self, visit_item, &krate.items); visit::walk_list!(self, visit_attribute, &krate.attrs); self.contains_macro_use(&krate.attrs); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9cdf79ca57d87..08fee7768dc90 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3255,7 +3255,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .iter() .filter_map(|item| { - let parent_scope = self.opt_local_def_id(item.parent_scope)?.to_def_id(); + let parent_scope = self.local_modules.iter().find_map(|m| match m.kind { + ModuleKind::Def(_, def_id, node_id, _) if node_id == item.parent_scope => { + Some(def_id) + } + _ => None, + })?; Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg.clone() }) }) .collect::>(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 693e49995c1cc..f4ea63fb2c7c4 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -211,7 +211,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); // Update effective visibilities of nested items. // If it's a mod, also make the visitor walk all of its items match item.kind { @@ -234,16 +234,16 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> ast::ItemKind::Enum(_, _, EnumDef { ref variants }) => { self.set_bindings_effective_visibilities(def_id); for variant in variants { - let variant_def_id = self.r.local_def_id(variant.id); + let variant_def_id = self.r.child_id(item.id, variant.id); for field in variant.data.fields() { - self.update_field(self.r.local_def_id(field.id), variant_def_id); + self.update_field(self.r.child_id(item.id, field.id), variant_def_id); } } } ast::ItemKind::Struct(_, _, ref def) | ast::ItemKind::Union(_, _, ref def) => { for field in def.fields() { - self.update_field(self.r.local_def_id(field.id), def_id); + self.update_field(self.r.child_id(item.id, field.id), def_id); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3337a4626b040..1cabf0056f262 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -692,7 +692,11 @@ enum MaybeExported<'a> { impl MaybeExported<'_> { fn eval(self, r: &Resolver<'_, '_>) -> bool { let def_id = match self { - MaybeExported::Ok(node_id) => Some(r.local_def_id(node_id)), + MaybeExported::Ok(node_id) => Some(if r.current_owner.id == node_id { + r.current_owner.def_id + } else { + r.current_owner.node_id_to_def_id[&node_id] + }), MaybeExported::Impl(Some(trait_def_id)) | MaybeExported::ImplItem(Ok(trait_def_id)) => { trait_def_id.as_local() } @@ -833,7 +837,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc let prev = replace(&mut self.diag_metadata.current_item, Some(item)); // Always report errors in items we just entered. let old_ignore = replace(&mut self.in_func_body, false); - self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)); + self.with_owner(item.id, |this| { + this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)) + }); self.in_func_body = old_ignore; self.diag_metadata.current_item = prev; } @@ -1042,36 +1048,38 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc ); } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { - self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); - let def_kind = self.r.local_def_kind(foreign_item.id); - match foreign_item.kind { - ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - foreign_item.id, - LifetimeBinderKind::Item, - generics.span, - |this| visit::walk_item(this, foreign_item), - ); - } - ForeignItemKind::Fn(box Fn { ref generics, .. }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - foreign_item.id, - LifetimeBinderKind::Function, - generics.span, - |this| visit::walk_item(this, foreign_item), - ); - } - ForeignItemKind::Static(..) => { - self.with_static_rib(def_kind, |this| visit::walk_item(this, foreign_item)) - } - ForeignItemKind::MacCall(..) => { - panic!("unexpanded macro in resolve!") + self.with_owner(foreign_item.id, |this| { + this.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); + let def_kind = this.r.tcx.def_kind(this.r.def_id); + match foreign_item.kind { + ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { + this.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), + foreign_item.id, + LifetimeBinderKind::Item, + generics.span, + |this| visit::walk_item(this, foreign_item), + ); + } + ForeignItemKind::Fn(box Fn { ref generics, .. }) => { + this.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), + foreign_item.id, + LifetimeBinderKind::Function, + generics.span, + |this| visit::walk_item(this, foreign_item), + ); + } + ForeignItemKind::Static(..) => { + this.with_static_rib(def_kind, |this| visit::walk_item(this, foreign_item)) + } + ForeignItemKind::MacCall(..) => { + panic!("unexpanded macro in resolve!") + } } - } + }) } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: NodeId) { let previous_value = self.diag_metadata.current_function; @@ -1710,6 +1718,28 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }) } + #[instrument(level = "debug", skip(self, work))] + fn with_owner(&mut self, owner: NodeId, work: impl FnOnce(&mut Self) -> T) -> T { + let old_owner = std::mem::replace( + &mut self.r.current_owner, + self.r.owners.remove(&owner).unwrap_or_else(|| { + panic!( + "unknown owner {owner}: {:?}", + self.r + .owners + .items() + .filter(|o| o.1.node_id_to_def_id.contains_key(&owner)) + .get_only() + .map(|(_, o)| o.node_id_to_def_id[&owner]) + ) + }), + ); + let ret = work(self); + let prev = std::mem::replace(&mut self.r.current_owner, old_owner); + self.r.owners.insert(prev.id, prev); + ret + } + #[instrument(level = "debug", skip(self, work))] fn with_lifetime_rib( &mut self, @@ -2737,7 +2767,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); - let kind = self.r.local_def_kind(item.id); + let kind = self.r.tcx.def_kind(self.r.def_id); self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, @@ -2746,7 +2776,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let item_def_id = this.r.local_def_id(item.id).to_def_id(); + let item_def_id = this.r.def_id.to_def_id(); this.with_self_rib( Res::SelfTyAlias { alias_to: item_def_id, is_trait_impl: false }, |this| { @@ -2807,7 +2837,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving item) resolving {:?} ({:?})", item.kind.ident(), item.kind); - let def_kind = self.r.local_def_kind(item.id); + let def_kind = self.r.tcx.def_kind(self.r.current_owner.def_id); match &item.kind { ItemKind::TyAlias(box TyAlias { generics, .. }) => { self.with_generic_param_rib( @@ -2863,7 +2893,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); + let local_def_id = this.r.def_id.to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); @@ -2882,7 +2912,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); + let local_def_id = this.r.def_id.to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::Bound); @@ -2892,7 +2922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - let module = self.r.expect_module(self.r.local_def_id(item.id).to_def_id()); + let module = self.r.expect_module(self.r.def_id.to_def_id()); let orig_module = replace(&mut self.parent_scope.module, module); self.with_rib(ValueNS, RibKind::Module(module.expect_local()), |this| { this.with_rib(TypeNS, RibKind::Module(module.expect_local()), |this| { @@ -3023,7 +3053,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Maintain macro_rules scopes in the same way as during early resolution // for diagnostics and doc links. if macro_def.macro_rules { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.def_id; self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } @@ -3318,6 +3348,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let trait_assoc_items = replace(&mut self.diag_metadata.current_trait_assoc_items, Some(trait_items)); + for item in trait_items { + self.with_owner(item.id, |this| this.resolve_trait_item(item)); + } + + self.diag_metadata.current_trait_assoc_items = trait_assoc_items; + } + + fn resolve_trait_item(&mut self, item: &'ast Item) { let walk_assoc_item = |this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| { this.with_generic_param_rib( @@ -3330,87 +3368,83 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); }; - for item in trait_items { - self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); - match &item.kind { - AssocItemKind::Const(box ast::ConstItem { - generics, - ty, - rhs_kind, - define_opaque, - .. - }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::AssocItem, - item.id, - LifetimeBinderKind::ConstItem, - generics.span, - |this| { - this.with_lifetime_rib( - LifetimeRibKind::StaticIfNoLifetimeInScope { - lint_id: item.id, - emit_lint: false, - }, - |this| { - this.visit_generics(generics); - if rhs_kind.is_type_const() - && !this.r.tcx.features().generic_const_parameter_types() - { - this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { - this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { - this.with_lifetime_rib( - LifetimeRibKind::ConstParamTy, - |this| this.visit_ty(ty), - ) - }) - }); - } else { - this.visit_ty(ty); - } - - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - // - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_item_rhs(rhs_kind, None); - }, - ) - }, - ); + self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); + match &item.kind { + AssocItemKind::Const(box ast::ConstItem { + generics, + ty, + rhs_kind, + define_opaque, + .. + }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, + |this| { + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + emit_lint: false, + }, + |this| { + this.visit_generics(generics); + if rhs_kind.is_type_const() + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } - self.resolve_define_opaques(define_opaque); - } - AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { - walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + // + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_item_rhs(rhs_kind, None); + }, + ) + }, + ); - self.resolve_define_opaques(define_opaque); - } - AssocItemKind::Delegation(delegation) => { - self.with_generic_param_rib( - &[], - RibKind::AssocItem, - item.id, - LifetimeBinderKind::Function, - delegation.path.segments.last().unwrap().ident.span, - |this| this.resolve_delegation(delegation, item.id, false), - ); - } - AssocItemKind::Type(box TyAlias { generics, .. }) => self - .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { - walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) - }), - AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { - panic!("unexpanded macro in resolve!") - } - }; - } + self.resolve_define_opaques(define_opaque); + } + AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { + walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); - self.diag_metadata.current_trait_assoc_items = trait_assoc_items; + self.resolve_define_opaques(define_opaque); + } + AssocItemKind::Delegation(delegation) => { + self.with_generic_param_rib( + &[], + RibKind::AssocItem, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, + |this| this.resolve_delegation(delegation, item.id, false), + ); + } + AssocItemKind::Type(box TyAlias { generics, .. }) => self + .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) + }), + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { + panic!("unexpanded macro in resolve!") + } + }; } /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). @@ -3473,7 +3507,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), + RibKind::Item(HasGenericParams::Yes(generics.span), self.r.tcx.def_kind(self.r.def_id)), item_id, LifetimeBinderKind::ImplBlock, generics.span, @@ -3493,7 +3527,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this, trait_id| { this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id)); - let item_def_id = this.r.local_def_id(item_id); + let item_def_id = this.r.def_id; // Register the trait definitions from here. if let Some(trait_id) = trait_id { @@ -3525,7 +3559,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); let mut seen_trait_items = Default::default(); for item in impl_items { - this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id, of_trait.is_some()); + this.with_owner(item.id, |this| { + this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id, of_trait.is_some()); + }) } }); }); @@ -3769,7 +3805,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // HACK: because we don't want to track the `TyCtxtFeed` through the resolver to here // in a hash-map, we instead conjure a `TyCtxtFeed` for any `DefId` here, but prevent // it from being used generally. - this.r.tcx.feed_visibility_for_trait_impl_item(this.r.local_def_id(id), vis); + this.r.tcx.feed_visibility_for_trait_impl_item(this.r.def_id, vis); }; let Some(decl) = decl else { @@ -3884,7 +3920,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_path(&delegation.path); self.r.delegation_infos.insert( - self.r.local_def_id(item_id), + self.r.def_id, DelegationInfo { resolution_node: if is_in_trait_impl { item_id } else { delegation.id }, }, @@ -5049,7 +5085,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { && let ItemKind::MacroDef(..) = item.kind { num_macro_definition_ribs += 1; - let res = self.r.local_def_id(item.id).to_def_id(); + let res = self.r.owner_id(item.id).to_def_id(); self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res))); } @@ -5544,7 +5580,7 @@ impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) { self.r .delegation_fn_sigs - .insert(self.r.local_def_id(id), DelegationFnSig { has_self: decl.has_self() }); + .insert(self.r.owner_id(id), DelegationFnSig { has_self: decl.has_self() }); } } @@ -5590,7 +5626,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { self.collect_fn_info(&sig.decl, item.id); } - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); let count = generics .params .iter() @@ -5632,7 +5668,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } if let AssocItemKind::Type(box ast::TyAlias { generics, .. }) = &item.kind { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); if let Some(suggestion) = required_generic_args_suggestion(generics) { self.r.item_required_generic_args_suggestions.insert(def_id, suggestion); } @@ -5643,18 +5679,21 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { - visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); - let mut late_resolution_visitor = LateResolutionVisitor::new(self); - late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); - visit::walk_crate(&mut late_resolution_visitor, krate); - for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { - self.lint_buffer.buffer_lint( - lint::builtin::UNUSED_LABELS, - *id, - *span, - errors::UnusedLabel, - ); - } + self.with_owner(CRATE_NODE_ID, |this| { + visit::walk_crate(&mut ItemInfoCollector { r: this }, krate); + let mut late_resolution_visitor = LateResolutionVisitor::new(this); + late_resolution_visitor + .resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); + visit::walk_crate(&mut late_resolution_visitor, krate); + for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { + this.lint_buffer.buffer_lint( + lint::builtin::UNUSED_LABELS, + *id, + *span, + errors::UnusedLabel, + ); + } + }) } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6f86759d46c5f..a71ee45687f4c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -12,6 +12,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::unord::UnordItems; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize, @@ -2672,7 +2673,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .extern_crate_map .items() // FIXME: This doesn't include impls like `impl Default for String`. - .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait))) + .flat_map(|(_, crate_)| { + UnordItems::wrap( + self.r.tcx.implementations_of_trait((*crate_, default_trait)).into_iter(), + ) + }) .filter_map(|(_, simplified_self_ty)| *simplified_self_ty) .filter_map(|simplified_self_ty| match simplified_self_ty { SimplifiedType::Adt(did) => Some(did), @@ -2775,8 +2780,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ast::AssocItemKind::Delegation(..) if self .r - .delegation_fn_sigs - .get(&self.r.local_def_id(assoc_item.id)) + .owners + .get(&assoc_item.id) + .and_then(|o| self.r.delegation_fn_sigs.get(&o.def_id)) .is_some_and(|sig| sig.has_self) => { AssocSuggestion::MethodWithSelf { called } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e5038f2d7f2b9..fc448adea6aa2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -39,14 +39,14 @@ use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{ - self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, - Generics, NodeId, Path, attr, + self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, DUMMY_NODE_ID, Expr, ExprKind, + GenericArg, GenericArgs, Generics, NodeId, Path, attr, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; -use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_data_structures::unord::{UnordItems, UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -66,15 +66,15 @@ use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, DelegationInfo, MainDefinition, RegisteredTools, ResolverAstLowering, ResolverGlobalCtxt, - TyCtxt, TyCtxtFeed, Visibility, + self, DelegationInfo, MainDefinition, PerOwnerResolverData, RegisteredTools, + ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; -use tracing::debug; +use tracing::{debug, instrument}; type Res = def::Res; @@ -188,6 +188,7 @@ struct InvocationParent { impl_trait_context: ImplTraitContext, in_attr: bool, const_arg_context: ConstArgContext, + owner: NodeId, } impl InvocationParent { @@ -196,6 +197,7 @@ impl InvocationParent { impl_trait_context: ImplTraitContext::Existential, in_attr: false, const_arg_context: ConstArgContext::NonDirect, + owner: CRATE_NODE_ID, }; } @@ -1440,7 +1442,11 @@ pub struct Resolver<'ra, 'tcx> { next_node_id: NodeId = CRATE_NODE_ID, - node_id_to_def_id: NodeMap, + /// Preserves per owner data once the owner is finished resolving. + owners: NodeMap, + + /// An entry of `owners` that gets taken out and reinserted whenever an owner is handled. + current_owner: PerOwnerResolverData, disambiguators: LocalDefIdMap, @@ -1500,6 +1506,22 @@ pub struct Resolver<'ra, 'tcx> { impl_trait_names: FxHashMap = default::fx_hash_map(), } +impl<'ra, 'tcx> std::ops::DerefMut for Resolver<'ra, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + assert_ne!(self.current_owner.id, DUMMY_NODE_ID); + &mut self.current_owner + } +} + +impl<'ra, 'tcx> std::ops::Deref for Resolver<'ra, 'tcx> { + type Target = PerOwnerResolverData; + + fn deref(&self) -> &Self::Target { + assert_ne!(self.current_owner.id, DUMMY_NODE_ID); + &self.current_owner + } +} + /// This provides memory for the rest of the crate. The `'ra` lifetime that is /// used by many types in this crate is an abbreviation of `ResolverArenas`. #[derive(Default)] @@ -1608,6 +1630,20 @@ impl<'ra, 'tcx> AsRef> for Resolver<'ra, 'tcx> { } impl<'tcx> Resolver<'_, 'tcx> { + /// Only call this in analyses after the resolver has finished. + /// Panics if the node id is currently not in the owner storage, + /// e.g. because it's further up in the current visitor stack. + fn owner_id(&self, owner: NodeId) -> LocalDefId { + self.owners[&owner].def_id + } + + /// Only call this in analyses after the resolver has finished. + /// Panics if the node id is currently not in the owner storage, + /// e.g. because it's further up in the current visitor stack. + fn child_id(&self, owner: NodeId, id: NodeId) -> LocalDefId { + self.owners[&owner].node_id_to_def_id[&id] + } + fn opt_local_def_id(&self, node: NodeId) -> Option { self.node_id_to_def_id.get(&node).copied() } @@ -1616,10 +1652,6 @@ impl<'tcx> Resolver<'_, 'tcx> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - fn local_def_kind(&self, node: NodeId) -> DefKind { - self.tcx.def_kind(self.local_def_id(node)) - } - /// Adds a definition with a parent definition. fn create_def( &mut self, @@ -1629,6 +1661,7 @@ impl<'tcx> Resolver<'_, 'tcx> { def_kind: DefKind, expn_id: ExpnId, span: Span, + is_owner: bool, ) -> TyCtxtFeed<'tcx, LocalDefId> { assert!( !self.node_id_to_def_id.contains_key(&node_id), @@ -1658,7 +1691,7 @@ impl<'tcx> Resolver<'_, 'tcx> { // Some things for which we allocate `LocalDefId`s don't correspond to // anything in the AST, so they don't have a `NodeId`. For these cases // we don't need a mapping from `NodeId` to `LocalDefId`. - if node_id != ast::DUMMY_NODE_ID { + if node_id != ast::DUMMY_NODE_ID && !is_owner { debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.node_id_to_def_id.insert(node_id, def_id); } @@ -1705,12 +1738,19 @@ impl<'tcx> Resolver<'_, 'tcx> { } /// This function is very slow, as it iterates over the entire - /// [Resolver::node_id_to_def_id] map just to find the [NodeId] + /// [PerOwnerResolverData::node_id_to_def_id] map for all [Resolver::owners] + /// just to find the [NodeId] /// that corresponds to the given [LocalDefId]. Only use this in - /// diagnostics code paths. + /// diagnostics code paths. Do not use this during macro expansion, + /// as it will not find any node ids within your current expansion's stack. fn def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId { - self.node_id_to_def_id + self.owners .items() + .flat_map(|(_, data)| { + data.node_id_to_def_id + .items() + .chain(UnordItems::wrap([(&data.id, &data.def_id)].into_iter())) + }) .filter(|(_, v)| **v == def_id) .map(|(k, _)| *k) .get_only() @@ -1748,11 +1788,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); let empty_module = empty_module.expect_local(); - let mut node_id_to_def_id = NodeMap::default(); + let owner_data = PerOwnerResolverData::new(CRATE_NODE_ID, CRATE_DEF_ID); let crate_feed = tcx.create_local_crate_def_id(crate_span); crate_feed.def_kind(DefKind::Mod); - node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID); + let mut owners = NodeMap::default(); + owners.insert(CRATE_NODE_ID, owner_data); let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); @@ -1815,7 +1856,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), - node_id_to_def_id, + owners, + current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), @@ -1917,7 +1959,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .into_iter() .filter_map(|item| { - let parent_scope = self.node_id_to_def_id.get(&item.parent_scope)?.to_def_id(); + let parent_scope = self.owners.get(&item.parent_scope)?.def_id.to_def_id(); Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg }) }) .collect(); @@ -1952,7 +1994,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetimes_res_map: self.lifetimes_res_map, extra_lifetime_params_map: self.extra_lifetime_params_map, next_node_id: self.next_node_id, - node_id_to_def_id: self.node_id_to_def_id, + owners: self.owners, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), @@ -2611,6 +2653,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.main_def = Some(MainDefinition { res, is_import, span }); } + + #[instrument(level = "debug", skip(self, work))] + fn with_owner(&mut self, owner: NodeId, work: impl FnOnce(&mut Self) -> T) -> T { + let old_owner = + std::mem::replace(&mut self.current_owner, self.owners.remove(&owner).unwrap()); + let ret = work(self); + assert!( + self.owners + .insert(owner, std::mem::replace(&mut self.current_owner, old_owner)) + .is_none() + ); + ret + } } fn build_extern_prelude<'tcx, 'ra>( diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f4464138ef1fc..4d7bccd8f4f1c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -4,7 +4,7 @@ use std::mem; use std::sync::Arc; -use rustc_ast::{self as ast, Crate, DelegationSuffixes, NodeId}; +use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; @@ -18,10 +18,10 @@ use rustc_expand::expand::{ }; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LocalDefId}; use rustc_hir::{Attribute, StabilityLevel}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt}; +use rustc_middle::ty::{PerOwnerResolverData, RegisteredTools, TyCtxt}; use rustc_session::Session; use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ @@ -165,7 +165,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn mark_scope_with_compile_error(&mut self, id: NodeId) { - if let Some(id) = self.opt_local_def_id(id) + if let Some(id) = self.owners.get(&id).map(|i| i.def_id) && self.tcx.def_kind(id).is_module_like() { self.mods_with_parse_errors.insert(id.to_def_id()); @@ -216,8 +216,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { features: &[Symbol], parent_module_id: Option, ) -> LocalExpnId { - let parent_module = - parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id()); + let parent_module = parent_module_id.map(|module_id| self.owner_id(module_id).to_def_id()); let expn_id = self.tcx.with_stable_hashing_context(|hcx| { LocalExpnId::fresh( ExpnData::allow_unstable( @@ -491,7 +490,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn declare_proc_macro(&mut self, id: NodeId) { - self.proc_macros.push(self.local_def_id(id)) + self.proc_macros.push(self.owner_id(id)) } fn append_stripped_cfg_item( @@ -555,6 +554,32 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) { self.impl_trait_names.insert(id, name); } + + fn set_owner(&mut self, id: NodeId) -> NodeId { + assert_ne!(id, DUMMY_NODE_ID); + let old = std::mem::replace(&mut self.current_owner, self.owners.remove(&id).unwrap()); + let old_id = old.id; + if old.id == DUMMY_NODE_ID { + if cfg!(debug_assertions) { + let PerOwnerResolverData { node_id_to_def_id, id: _, def_id: _ } = old; + assert!(node_id_to_def_id.is_empty()); + } + } else { + assert!(self.owners.insert(old.id, old).is_none()); + } + old_id + } + + fn reset_owner(&mut self, id: NodeId) { + let new = if id == DUMMY_NODE_ID { + PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID) + } else { + self.owners.remove(&id).unwrap() + }; + let old = std::mem::replace(&mut self.current_owner, new); + assert_ne!(old.id, DUMMY_NODE_ID); + assert!(self.owners.insert(old.id, old).is_none()); + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diff --git a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs index 8ae91bbcd2a91..2d604e02cf2cc 100644 --- a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::res::MaybeDef; use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, sym}; +use rustc_data_structures::unord::UnordItems; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ @@ -130,7 +131,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); let is_empty_method_found = current_and_super_traits .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) + .flat_map(|&i| UnordItems::wrap(cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty))) .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); if !is_empty_method_found { diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 6b81b9d117a37..85235e7cca047 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -6,6 +6,7 @@ use clippy_utils::{is_self, is_self_ty}; use core::ops::ControlFlow; use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::unord::UnordItems; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::attrs::InlineAttr; @@ -181,7 +182,7 @@ impl PassByRefOrValue { || typeck .adjustments() .items() - .flat_map(|(_, a)| a) + .flat_map(|(_, a)| UnordItems::wrap(a.iter())) .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer)))) { continue;