diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 61da931df4d5d..184ec2b8d0336 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -9,9 +9,8 @@ use std::sync::Arc; use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind}; use rustc_ast::{ - self as ast, AssocItem, AssocItemKind, Block, ConstItem, DUMMY_NODE_ID, Delegation, Fn, - ForeignItem, ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TraitAlias, - TyAlias, + self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem, + ForeignItemKind, Inline, Item, ItemKind, NodeId, StaticItem, StmtKind, TraitAlias, TyAlias, }; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::{ResolverExpand, SyntaxExtension, SyntaxExtensionKind}; @@ -168,12 +167,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expn_id = self.cstore().expn_that_defined_untracked(self.tcx, def_id); let module = self.new_extern_module( parent, - ModuleKind::Def( - def_kind, - def_id, - DUMMY_NODE_ID, - Some(self.tcx.item_name(def_id)), - ), + def_kind, + def_id, + self.tcx.item_name(def_id), expn_id, self.def_span(def_id), // FIXME: Account for `#[no_implicit_prelude]` attributes. @@ -253,7 +249,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match vis.kind { ast::VisibilityKind::Public => Ok(Visibility::Public), ast::VisibilityKind::Inherited => { - Ok(match parent_scope.module.kind { + Ok(match parent_scope.module.expect_local().kind { // Any inherited visibility resolved directly inside an enum or trait // (i.e. variants, fields, and trait items) inherits from the visibility // of the enum or trait. @@ -350,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn build_reduced_graph_external(&self, module: ExternModule<'ra>) { - let def_id = module.def_id(); + let def_id = module.def_id; let children = self.tcx.module_children(def_id); for (i, child) in children.iter().enumerate() { self.build_reduced_graph_for_external_crate_res(child, module, i, None) @@ -535,7 +531,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { root_id: NodeId, vis: Visibility, ) { - let current_module = self.parent_scope.module; + let current_module = self.parent_scope.module.expect_local(); let import = self.r.arenas.alloc_import(ImportData { kind, parent_scope: self.parent_scope, @@ -560,7 +556,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { if target.name != kw::Underscore { self.r.per_ns(|this, ns| { let key = BindingKey::new(IdentKey::new(target), ns); - this.resolution_or_default(current_module, key, target.span) + this.resolution_or_default(current_module.to_module(), key, target.span) .borrow_mut(this) .single_imports .insert(import); @@ -1136,7 +1132,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) = AttributeParser::parse_limited(self.r.tcx.sess, &item.attrs, &[sym::macro_use]) { - if self.parent_scope.module.parent.is_some() { + if self.parent_scope.module.expect_local().parent.is_some() { self.r .dcx() .emit_err(errors::ExternCrateLoadingMacroNotAtCrateRoot { span: item.span }); @@ -1247,7 +1243,8 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { /// directly into its parent scope's module. pub(crate) fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> { let invoc_id = self.visit_invoc(id); - self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id); + let module = self.parent_scope.module.expect_local(); + module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5e52ebcc3f194..5b38d820dde65 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -240,7 +240,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.report_conflict(ident, ns, new_binding, old_binding); } - let container = match old_binding.parent_module.unwrap().kind { + let container = match old_binding.parent_module.unwrap().expect_local().kind { // Avoid using TyCtxt::def_kind_descr in the resolver, because it // indirectly *calls* the resolver, and would cause a query cycle. ModuleKind::Def(kind, def_id, _, _) => kind.descr(def_id), @@ -1757,7 +1757,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } return; } - if Some(parent_nearest) == scope.opt_def_id() { + if Some(parent_nearest) == scope.kind.opt_def_id() { err.subdiagnostic(MacroDefinedLater { span: unused_ident.span }); err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident }); return; @@ -1765,7 +1765,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if ident.name == kw::Default - && let ModuleKind::Def(DefKind::Enum, def_id, _, _) = parent_scope.module.kind + && let ModuleKind::Def(DefKind::Enum, def_id, _, _) = parent_scope.module.kind() { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); @@ -1894,7 +1894,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident.name, ); let sugg_span = - if let ModuleKind::Def(DefKind::Enum, id, _, _) = parent_scope.module.kind { + if let ModuleKind::Def(DefKind::Enum, id, _, _) = parent_scope.module.kind() { let span = self.def_span(id); if span.from_expansion() { None @@ -2607,7 +2607,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = module.to_module(); current_module.is_ancestor_of(module) && current_module != module }) - .flat_map(|(_, module)| module.kind.name()), + .map(|(_, module)| module.name), ) .filter(|c| !c.to_string().is_empty()) .collect::>(); @@ -2631,8 +2631,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> (String, String, Option) { let is_last = failed_segment_idx == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; - let module_res = match module { - Some(ModuleOrUniformRoot::Module(module)) => module.res(), + let module_def_id = match module { + Some(ModuleOrUniformRoot::Module(module)) => module.opt_def_id(), _ => None, }; let scope = match &path[..failed_segment_idx] { @@ -2647,7 +2647,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let message = format!("cannot find `{ident}` in {scope}"); - if module_res == self.graph_root.res() { + if module_def_id == Some(CRATE_DEF_ID.to_def_id()) { let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _)); let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); candidates @@ -3128,7 +3128,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; }; - while let Some(parent) = crate_module.parent { + while let Some(parent) = crate_module.parent() { crate_module = parent; } @@ -3145,7 +3145,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !kinds.contains(MacroKinds::BANG) { return None; } - let module_name = crate_module.kind.name().unwrap_or(kw::Crate); + let module_name = crate_module.name().unwrap_or(kw::Crate); let import_snippet = match import.kind { ImportKind::Single { source, target, .. } if source != target => { format!("{source} as {target}") @@ -3290,20 +3290,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return cached; } visited.insert(parent_module, false); - let m = r.expect_module(parent_module); let mut res = false; - for importer in m.glob_importers.borrow().iter() { - if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() { - if next_parent_module == module - || comes_from_same_module_for_glob( - r, - next_parent_module, - module, - visited, - ) + if let Module::Local(m) = r.expect_module(parent_module) { + for importer in m.glob_importers.borrow().iter() { + if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() { - res = true; - break; + if next_parent_module == module + || comes_from_same_module_for_glob( + r, + next_parent_module, + module, + visited, + ) + { + res = true; + break; + } } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b33b77d43999d..b855857a92ea5 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -247,8 +247,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Some((self.expn_def_scope(expn_id), None)); } - if let ModuleKind::Block = module.kind { - return Some((module.parent.unwrap().nearest_item_scope(), None)); + if let ModuleKind::Block = module.kind() { + return Some((module.parent().unwrap().nearest_item_scope(), None)); } // We need to support the next case under a deprecation warning @@ -263,7 +263,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // ``` // So we have to fall back to the module's parent during lexical resolution in this case. if derive_fallback_lint_id.is_some() - && let Some(parent) = module.parent + && let Some(parent) = module.parent() // Inner module is inside the macro && module.expansion != parent.expansion // Parent module is outside of the macro @@ -643,14 +643,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(ControlFlow::Break(..)) => return decl, } } - Scope::ModuleGlobs(module, _) - if let ModuleKind::Def(_, def_id, _, _) = module.kind - && !def_id.is_local() => - { + Scope::ModuleGlobs(Module::Extern(_), _) => { // Fast path: external module decoding only creates non-glob declarations. Err(Determined) } - Scope::ModuleGlobs(module, derive_fallback_lint_id) => { + Scope::ModuleGlobs(Module::Local(module), derive_fallback_lint_id) => { let (adjusted_parent_scope, adjusted_finalize) = if matches!( scope_set, ScopeSet::Module(..) | ScopeSet::ModuleAndExternPrelude(..) @@ -658,12 +655,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { (parent_scope, finalize) } else { ( - &ParentScope { module, ..*parent_scope }, + &ParentScope { module: module.to_module(), ..*parent_scope }, finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; let binding = self.reborrow().resolve_ident_in_module_globs_unadjusted( - module.expect_local(), + module, ident, orig_ident_span, ns, @@ -699,9 +696,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() { Some(decl) => Ok(decl), - None => Err(Determinacy::determined( - self.graph_root.unexpanded_invocations.borrow().is_empty(), - )), + None => Err(Determinacy::determined(!self.graph_root.has_unexpanded_invocations())), }, Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) { Some(decl) => Ok(*decl), @@ -714,9 +709,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.is_some(), ) { Some(decl) => Ok(decl), - None => Err(Determinacy::determined( - self.graph_root.unexpanded_invocations.borrow().is_empty(), - )), + None => { + Err(Determinacy::determined(!self.graph_root.has_unexpanded_invocations())) + } } } Scope::ExternPreludeFlags => { @@ -966,7 +961,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); module .unwrap_or_else(|| self.resolve_self(&mut ctxt, parent_scope.module)) - .parent + .parent() .map(|parent| self.resolve_self(&mut ctxt, parent)) } @@ -1126,6 +1121,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return if accessible { Ok(binding) } else { Err(ControlFlow::Break(Determined)) }; } + // In extern modules everything is determined from the start. + let Module::Local(module) = module else { + return Err(ControlFlow::Continue(Determined)); + }; + // Check if one of single imports can still define the name, block if it can. if self.reborrow().single_import_can_define_name( &resolution, @@ -1139,7 +1139,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Check if one of unexpanded macros can still define the name. - if !module.unexpanded_invocations.borrow().is_empty() { + if module.has_unexpanded_invocations() { return Err(ControlFlow::Continue(Undetermined)); } @@ -1223,7 +1223,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // scopes we return `Undetermined` with `ControlFlow::Continue`. // Check if one of unexpanded macros can still define the name, // if it can then our "no resolution" result is not determined and can be invalidated. - if !module.unexpanded_invocations.borrow().is_empty() { + if module.has_unexpanded_invocations() { return Err(ControlFlow::Continue(Undetermined)); } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b16347af7ba0c..76daf5fc2c033 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -43,9 +43,9 @@ use crate::errors::{ use crate::ref_mut::CmCell; use crate::{ AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize, - IdentKey, ImportSuggestion, ImportSummary, LocalModule, ModuleOrUniformRoot, ParentScope, - PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, - names_to_string, + IdentKey, ImportSuggestion, ImportSummary, LocalModule, Module, ModuleOrUniformRoot, + ParentScope, PathResult, PerNS, Res, ResolutionError, Resolver, ScopeSet, Segment, Used, + module_to_string, names_to_string, }; /// A potential import declaration in the process of being planted into a module. @@ -1790,7 +1790,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Add to module's glob_importers - module.glob_importers.borrow_mut_unchecked().push(import); + if let Module::Local(module) = module { + module.glob_importers.borrow_mut_unchecked().push(import); + } // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. @@ -1844,7 +1846,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut(self) = Vec::new(); - let Some(def_id) = module.opt_def_id() else { return }; + let Some(def_id) = module.kind.opt_def_id() else { return }; let mut children = Vec::new(); let mut ambig_children = Vec::new(); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3337a4626b040..a423f91fbe9cf 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1477,7 +1477,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; - let parent_scope = ParentScope::module(graph_root.to_module(), resolver.arenas); + let parent_scope = ParentScope::module(graph_root, resolver.arenas); let start_rib_kind = RibKind::Module(graph_root); LateResolutionVisitor { r: resolver, @@ -1942,7 +1942,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { && let Some(ty) = &self.diag_metadata.current_self_type && Some(true) == self.diag_metadata.in_non_gat_assoc_type && let crate::ModuleKind::Def(DefKind::Trait, trait_id, _, _) = - module.kind + module.kind() { if def_id_matches_path( self.r.tcx, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6f86759d46c5f..d7ce4f731e21b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -38,8 +38,8 @@ use crate::late::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Finalize, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Res, - Resolver, ScopeSet, Segment, errors, path_names_to_string, + Finalize, Module, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Res, Resolver, + ScopeSet, Segment, errors, path_names_to_string, }; /// A field or associated item from self type suggested in case of resolution failure. @@ -1698,7 +1698,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { && let TyKind::Path(_, self_ty_path) = &self_ty.kind && let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(&Segment::from_path(self_ty_path), Some(TypeNS), None, source) - && let ModuleKind::Def(DefKind::Trait, ..) = module.kind + && module.def_kind() == Some(DefKind::Trait) && trait_ref.path.span == span && let PathSource::Trait(_) = source && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res @@ -3014,12 +3014,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn find_module(&self, def_id: DefId) -> Option<(Module<'ra>, ImportSuggestion)> { let mut result = None; let mut seen_modules = FxHashSet::default(); - let root_did = self.r.graph_root.def_id(); - let mut worklist = vec![( - self.r.graph_root.to_module(), - ThinVec::new(), - root_did.is_local() || !self.r.tcx.is_doc_hidden(root_did), - )]; + let mut worklist = vec![(self.r.graph_root.to_module(), ThinVec::new(), true)]; while let Some((in_module, path_segments, doc_visible)) = worklist.pop() { // abort if the module is already found diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 879a4dd3983a6..3826fedddd2e2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -39,8 +39,8 @@ 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; @@ -61,7 +61,6 @@ use rustc_hir::definitions::{PerParentDisambiguatorState, PerParentDisambiguator use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::CStore; -use rustc_middle::bug; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; @@ -69,6 +68,7 @@ use rustc_middle::ty::{ self, DelegationInfo, MainDefinition, RegisteredTools, ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; +use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; @@ -172,9 +172,9 @@ struct ParentScope<'ra> { impl<'ra> ParentScope<'ra> { /// Creates a parent scope with the passed argument used as the module scope component, /// and other scope components set to default empty values. - fn module(module: Module<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { + fn module(module: LocalModule<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { ParentScope { - module, + module: module.to_module(), expansion: LocalExpnId::ROOT, macro_rules: arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], @@ -519,7 +519,7 @@ impl<'ra> PathResult<'ra> { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] enum ModuleKind { /// An anonymous module; e.g., just a block. /// @@ -648,118 +648,85 @@ type Resolutions<'ra> = CmRefCell { - /// The direct parent module (it may not be a `mod`, however). - parent: Option>, - /// What kind of module this is, because this may not be a `mod`. - kind: ModuleKind, - +/// You can use [`Module::kind`] to determine the kind of module this is. +struct CommonModuleData<'ra> { /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'ra>, - /// True if this is a module from other crate that needs to be populated on access. - populate_on_access: CacheCell, - /// Used to disambiguate underscore items (`const _: T = ...`) in the module. - underscore_disambiguator: CmCell, - - /// Macro invocations that can expand into items in this module. - unexpanded_invocations: CmRefCell>, - /// Whether `#[no_implicit_prelude]` is active. no_implicit_prelude: bool, - - glob_importers: CmRefCell>>, - globs: CmRefCell>>, - /// Used to memoize the traits in this module for faster searches through all traits in scope. traits: CmRefCell< Option, Option>, bool /* lint ambiguous */)]>>, >, - /// Span of the module itself. Used for error reporting. span: Span, - expansion: ExpnId, - /// Declaration for implicitly declared names that come with a module, /// like `self` (not yet used), or `crate`/`$crate` (for root modules). self_decl: Option>, } +struct LocalModuleData<'ra> { + common: CommonModuleData<'ra>, + /// What kind of module this is, because this may not be a `mod`. + kind: ModuleKind, + /// The direct parent module (it may not be a `mod`, however). + parent: Option>, + /// Used to disambiguate underscore items (`const _: T = ...`) in the module. + underscore_disambiguator: CmCell, + /// Macro invocations that can expand into items in this module. + unexpanded_invocations: CmRefCell>, + glob_importers: CmRefCell>>, + globs: CmRefCell>>, +} + +struct ExternModuleData<'ra> { + common: CommonModuleData<'ra>, + def_kind: DefKind, + def_id: DefId, + name: Symbol, + /// The direct parent module (it may not be a `mod`, however). + parent: Option>, + /// True if this is a module from other crate that needs to be populated on access. + populate_on_access: CacheCell, +} + /// All modules are unique and allocated on a same arena, /// so we can use referential equality to compare them. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] -struct Module<'ra>(Interned<'ra, ModuleData<'ra>>); +enum Module<'ra> { + Local(LocalModule<'ra>), + Extern(ExternModule<'ra>), +} /// Same as `Module`, but is guaranteed to be from the current crate. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] -struct LocalModule<'ra>(Interned<'ra, ModuleData<'ra>>); +struct LocalModule<'ra>(Interned<'ra, LocalModuleData<'ra>>); /// Same as `Module`, but is guaranteed to be from an external crate. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] -struct ExternModule<'ra>(Interned<'ra, ModuleData<'ra>>); - -// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the -// contained data. -// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees -// are upheld. -impl std::hash::Hash for ModuleData<'_> { - fn hash(&self, _: &mut H) - where - H: std::hash::Hasher, - { - unreachable!() - } -} +struct ExternModule<'ra>(Interned<'ra, ExternModuleData<'ra>>); -impl<'ra> ModuleData<'ra> { +impl<'ra> CommonModuleData<'ra> { fn new( - parent: Option>, - kind: ModuleKind, expansion: ExpnId, span: Span, no_implicit_prelude: bool, self_decl: Option>, ) -> Self { - let is_foreign = match kind { - ModuleKind::Def(_, def_id, _, _) => !def_id.is_local(), - ModuleKind::Block => false, - }; - ModuleData { - parent, - kind, + CommonModuleData { lazy_resolutions: Default::default(), - populate_on_access: CacheCell::new(is_foreign), - underscore_disambiguator: CmCell::new(0), - unexpanded_invocations: Default::default(), no_implicit_prelude, - glob_importers: CmRefCell::new(Vec::new()), - globs: CmRefCell::new(Vec::new()), traits: CmRefCell::new(None), span, expansion, self_decl, } } - - fn opt_def_id(&self) -> Option { - self.kind.opt_def_id() - } - - fn def_id(&self) -> DefId { - self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") - } - - fn res(&self) -> Option { - match self.kind { - ModuleKind::Def(kind, def_id, _, _) => Some(Res::Def(kind, def_id)), - _ => None, - } - } } impl<'ra> Module<'ra> { @@ -813,17 +780,17 @@ impl<'ra> Module<'ra> { // `self` resolves to the first module ancestor that `is_normal`. fn is_normal(self) -> bool { - matches!(self.kind, ModuleKind::Def(DefKind::Mod, _, _, _)) + self.def_kind() == Some(DefKind::Mod) } fn is_trait(self) -> bool { - matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _, _)) + matches!(self.def_kind(), Some(DefKind::Trait)) } fn nearest_item_scope(self) -> Module<'ra> { - match self.kind { - ModuleKind::Def(DefKind::Enum | DefKind::Trait, ..) => { - self.parent.expect("enum or trait module without a parent") + match self.def_kind() { + Some(DefKind::Enum | DefKind::Trait) => { + self.parent().expect("enum or trait module without a parent") } _ => self, } @@ -832,24 +799,26 @@ impl<'ra> Module<'ra> { /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). /// This may be the crate root. fn nearest_parent_mod(self) -> DefId { - match self.kind { + match self.kind() { ModuleKind::Def(DefKind::Mod, def_id, _, _) => def_id, - _ => self.parent.expect("non-root module without parent").nearest_parent_mod(), + _ => self.parent().expect("non-root module without parent").nearest_parent_mod(), } } /// The [`NodeId`] of the nearest `mod` item ancestor (which may be this module). /// This may be the crate root. fn nearest_parent_mod_node_id(self) -> NodeId { - match self.kind { + match self.kind() { ModuleKind::Def(DefKind::Mod, _, node_id, _) => node_id, - _ => self.parent.expect("non-root module without parent").nearest_parent_mod_node_id(), + _ => { + self.parent().expect("non-root module without parent").nearest_parent_mod_node_id() + } } } fn is_ancestor_of(self, mut other: Self) -> bool { while self != other { - if let Some(parent) = other.parent { + if let Some(parent) = other.parent() { other = parent; } else { return false; @@ -860,66 +829,202 @@ impl<'ra> Module<'ra> { #[track_caller] fn expect_local(self) -> LocalModule<'ra> { - match self.kind { - ModuleKind::Def(_, def_id, _, _) if !def_id.is_local() => { - panic!("`Module::expect_local` is called on a non-local module: {self:?}") - } - ModuleKind::Def(..) | ModuleKind::Block => LocalModule(self.0), + match self { + Module::Local(m) => m, + Module::Extern(m) => span_bug!(m.span, "unexpected extern module: {m:?}"), } } #[track_caller] fn expect_extern(self) -> ExternModule<'ra> { - match self.kind { - ModuleKind::Def(_, def_id, _, _) if !def_id.is_local() => ExternModule(self.0), - ModuleKind::Def(..) | ModuleKind::Block => { - panic!("`Module::expect_extern` is called on a local module: {self:?}") - } + match self { + Module::Extern(m) => m, + Module::Local(m) => span_bug!(m.span, "unexpected local module: {m:?}"), + } + } + + fn has_unexpanded_invocations(self) -> bool { + match self { + Module::Local(m) => m.has_unexpanded_invocations(), + Module::Extern(_) => false, + } + } + + fn parent(self) -> Option> { + match self { + Module::Local(m) => m.parent.map(Module::Local), + Module::Extern(m) => m.parent.map(Module::Extern), + } + } + + #[inline] + fn kind(self) -> ModuleKind { + match self { + Module::Local(m) => m.kind, + Module::Extern(m) => ModuleKind::Def(m.def_kind, m.def_id, DUMMY_NODE_ID, Some(m.name)), + } + } + + fn opt_def_id(self) -> Option { + match self { + Module::Local(m) => m.kind.opt_def_id(), + Module::Extern(m) => Some(m.def_id), + } + } + + fn def_id(self) -> DefId { + self.opt_def_id().expect("`Module::def_id` is called on a block module") + } + + fn res(self) -> Option { + match self.kind() { + ModuleKind::Def(kind, def_id, _, _) => Some(Res::Def(kind, def_id)), + _ => None, + } + } + + fn name(self) -> Option { + match self { + Module::Local(m) => m.kind.name(), + Module::Extern(m) => Some(m.name), + } + } + + fn def_kind(self) -> Option { + match self { + Module::Local(m) => match m.kind { + ModuleKind::Block => None, + ModuleKind::Def(def_kind, ..) => Some(def_kind), + }, + Module::Extern(m) => Some(m.def_kind), } } } impl<'ra> LocalModule<'ra> { + fn new( + parent: Option>, + kind: ModuleKind, + vis: Visibility, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + arenas: &'ra ResolverArenas<'ra>, + ) -> LocalModule<'ra> { + let self_decl = match kind { + ModuleKind::Def(def_kind, def_id, ..) => { + assert!(def_id.is_local()); + let expn_id = expn_id.as_local().unwrap_or(LocalExpnId::ROOT); + let parent = parent.map(|m| m.to_module()); + Some(arenas.new_def_decl(Res::Def(def_kind, def_id), vis, span, expn_id, parent)) + } + ModuleKind::Block => None, + }; + let common = CommonModuleData::new(expn_id, span, no_implicit_prelude, self_decl); + let data = LocalModuleData { + common, + kind, + parent, + underscore_disambiguator: CmCell::new(0), + unexpanded_invocations: Default::default(), + glob_importers: Default::default(), + globs: Default::default(), + }; + LocalModule(Interned::new_unchecked(arenas.local_modules.alloc(data))) + } + fn to_module(self) -> Module<'ra> { - Module(self.0) + Module::Local(self) + } + + fn has_unexpanded_invocations(self) -> bool { + !self.unexpanded_invocations.borrow().is_empty() } } impl<'ra> ExternModule<'ra> { + fn new( + parent: Option>, + def_kind: DefKind, + def_id: DefId, + name: Symbol, + vis: Visibility, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + arenas: &'ra ResolverArenas<'ra>, + ) -> ExternModule<'ra> { + assert!(!def_id.is_local()); + let self_decl = { + let expn_id = expn_id.as_local().unwrap_or(LocalExpnId::ROOT); + let parent = parent.map(|m| m.to_module()); + Some(arenas.new_def_decl(Res::Def(def_kind, def_id), vis, span, expn_id, parent)) + }; + let common = CommonModuleData::new(expn_id, span, no_implicit_prelude, self_decl); + let data = ExternModuleData { + common, + def_kind, + def_id, + name, + parent, + populate_on_access: CacheCell::new(true), + }; + ExternModule(Interned::new_unchecked(arenas.extern_modules.alloc(data))) + } + fn to_module(self) -> Module<'ra> { - Module(self.0) + Module::Extern(self) } } impl<'ra> std::ops::Deref for Module<'ra> { - type Target = ModuleData<'ra>; + type Target = CommonModuleData<'ra>; fn deref(&self) -> &Self::Target { - &self.0 + match self { + Module::Local(m) => &m.common, + Module::Extern(m) => &m.common, + } } } impl<'ra> std::ops::Deref for LocalModule<'ra> { - type Target = ModuleData<'ra>; + type Target = LocalModuleData<'ra>; fn deref(&self) -> &Self::Target { &self.0 } } +impl<'ra> std::ops::Deref for LocalModuleData<'ra> { + type Target = CommonModuleData<'ra>; + + fn deref(&self) -> &Self::Target { + &self.common + } +} + impl<'ra> std::ops::Deref for ExternModule<'ra> { - type Target = ModuleData<'ra>; + type Target = ExternModuleData<'ra>; fn deref(&self) -> &Self::Target { &self.0 } } +impl<'ra> std::ops::Deref for ExternModuleData<'ra> { + type Target = CommonModuleData<'ra>; + + fn deref(&self) -> &Self::Target { + &self.common + } +} + impl<'ra> fmt::Debug for Module<'ra> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.kind { - ModuleKind::Block => write!(f, "block"), - ModuleKind::Def(..) => write!(f, "{:?}", self.res()), + match self.res() { + None => write!(f, "block"), + Some(res) => write!(f, "{:?}", res), } } } @@ -930,6 +1035,28 @@ impl<'ra> fmt::Debug for LocalModule<'ra> { } } +impl<'ra> fmt::Debug for ExternModule<'ra> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.to_module().fmt(f) + } +} + +// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the +// contained data. +// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees +// are upheld. +impl std::hash::Hash for LocalModuleData<'_> { + fn hash(&self, _: &mut H) { + unreachable!() + } +} + +impl std::hash::Hash for ExternModuleData<'_> { + fn hash(&self, _: &mut H) { + unreachable!() + } +} + /// Data associated with any name declaration. #[derive(Clone, Debug)] struct DeclData<'ra> { @@ -1208,8 +1335,7 @@ impl<'ra> DeclData<'ra> { fn determined(&self) -> bool { match &self.kind { DeclKind::Import { source_decl, import, .. } if import.is_glob() => { - import.parent_scope.module.unexpanded_invocations.borrow().is_empty() - && source_decl.determined() + !import.parent_scope.module.has_unexpanded_invocations() && source_decl.determined() } _ => true, } @@ -1504,7 +1630,8 @@ pub struct Resolver<'ra, 'tcx> { /// used by many types in this crate is an abbreviation of `ResolverArenas`. #[derive(Default)] pub struct ResolverArenas<'ra> { - modules: TypedArena>, + local_modules: TypedArena>, + extern_modules: TypedArena>, imports: TypedArena>, name_resolutions: TypedArena>>, ast_paths: TypedArena, @@ -1538,31 +1665,6 @@ impl<'ra> ResolverArenas<'ra> { self.new_def_decl(res, Visibility::Public, span, expn_id, None) } - fn new_module( - &'ra self, - parent: Option>, - kind: ModuleKind, - vis: Visibility, - expn_id: ExpnId, - span: Span, - no_implicit_prelude: bool, - ) -> Module<'ra> { - let self_decl = match kind { - ModuleKind::Def(def_kind, def_id, _, _) => { - let expn_id = expn_id.as_local().unwrap_or(LocalExpnId::ROOT); - Some(self.new_def_decl(Res::Def(def_kind, def_id), vis, span, expn_id, parent)) - } - ModuleKind::Block => None, - }; - Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( - parent, - kind, - expn_id, - span, - no_implicit_prelude, - self_decl, - )))) - } fn alloc_decl(&'ra self, data: DeclData<'ra>) -> Decl<'ra> { Interned::new_unchecked(self.dropless.alloc(data)) } @@ -1724,26 +1826,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { arenas: &'ra ResolverArenas<'ra>, ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); - let graph_root = arenas.new_module( + let graph_root = LocalModule::new( None, ModuleKind::Def(DefKind::Mod, root_def_id, CRATE_NODE_ID, None), Visibility::Public, ExpnId::root(), crate_span, attr::contains_name(attrs, sym::no_implicit_prelude), + arenas, ); - let graph_root = graph_root.expect_local(); let local_modules = vec![graph_root]; let local_module_map = FxIndexMap::from_iter([(CRATE_DEF_ID, graph_root)]); - let empty_module = arenas.new_module( + let empty_module = LocalModule::new( None, ModuleKind::Def(DefKind::Mod, root_def_id, CRATE_NODE_ID, None), Visibility::Public, ExpnId::root(), DUMMY_SP, true, + arenas, ); - let empty_module = empty_module.expect_local(); let mut node_id_to_def_id = NodeMap::default(); let crate_feed = tcx.create_local_crate_def_id(crate_span); @@ -1825,7 +1927,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .. }; - let root_parent_scope = ParentScope::module(graph_root.to_module(), resolver.arenas); + let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver.feed_visibility(crate_feed, Visibility::Public); @@ -1840,15 +1942,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, no_implicit_prelude: bool, ) -> LocalModule<'ra> { - let parent = parent.map(|m| m.to_module()); let vis = kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); - let module = self - .arenas - .new_module(parent, kind, vis, expn_id, span, no_implicit_prelude) - .expect_local(); + let module = + LocalModule::new(parent, kind, vis, expn_id, span, no_implicit_prelude, self.arenas); self.local_modules.push(module); - if let Some(def_id) = module.opt_def_id() { + if let Some(def_id) = module.kind.opt_def_id() { self.local_module_map.insert(def_id.expect_local(), module); } module @@ -1857,19 +1956,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn new_extern_module( &self, parent: Option>, - kind: ModuleKind, + def_kind: DefKind, + def_id: DefId, + name: Symbol, expn_id: ExpnId, span: Span, no_implicit_prelude: bool, ) -> ExternModule<'ra> { - let parent = parent.map(|m| m.to_module()); - let vis = - kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id)); - let module = self - .arenas - .new_module(parent, kind, vis, expn_id, span, no_implicit_prelude) - .expect_extern(); - self.extern_module_map.borrow_mut().insert(module.def_id(), module); + let module = ExternModule::new( + parent, + def_kind, + def_id, + name, + self.tcx.visibility(def_id), + expn_id, + span, + no_implicit_prelude, + self.arenas, + ); + self.extern_module_map.borrow_mut().insert(module.def_id, module); module } @@ -2145,11 +2250,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> { - if module.populate_on_access.get() { - module.populate_on_access.set(false); - self.build_reduced_graph_external(module.expect_extern()); + match module { + Module::Local(m) => &m.0.0.lazy_resolutions, + Module::Extern(m) => { + if m.populate_on_access.get() { + m.populate_on_access.set(false); + self.build_reduced_graph_external(m); + } + &m.0.0.lazy_resolutions + } } - &module.0.0.lazy_resolutions } fn resolution( @@ -2220,7 +2330,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { - let empty_module = self.empty_module.to_module(); + let empty_module = self.empty_module; let arenas = self.arenas; self.cm() .maybe_resolve_ident_in_module( @@ -2341,7 +2451,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})", ident, module, - module.kind.name(), + module.name(), ident.span ); module @@ -2350,7 +2460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_self(&self, ctxt: &mut SyntaxContext, module: Module<'ra>) -> Module<'ra> { let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { - let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); + let parent = module.parent().unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); module = self.expect_module(parent.nearest_parent_mod()); } module @@ -2586,12 +2696,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let module = self.graph_root.to_module(); + let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); let parent_scope = &ParentScope::module(module, self.arenas); let Ok(name_binding) = self.cm().maybe_resolve_ident_in_module( - ModuleOrUniformRoot::Module(module), + ModuleOrUniformRoot::Module(module.to_module()), ident, ValueNS, parent_scope, @@ -2685,22 +2795,9 @@ fn path_names_to_string(path: &Path) -> String { /// A somewhat inefficient routine to obtain the name of a module. fn module_to_string(mut module: Module<'_>) -> Option { let mut names = Vec::new(); - loop { - if let ModuleKind::Def(.., name) = module.kind { - if let Some(parent) = module.parent { - // `unwrap` is safe: the presence of a parent means it's not the crate root. - names.push(name.unwrap()); - module = parent - } else { - break; - } - } else { - names.push(sym::opaque_module_name_placeholder); - let Some(parent) = module.parent else { - return None; - }; - module = parent; - } + while let Some(parent) = module.parent() { + names.push(module.name().unwrap_or(sym::opaque_module_name_placeholder)); + module = parent; } if names.is_empty() { return None; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f4464138ef1fc..2a7b6be458d01 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -175,10 +175,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn resolve_dollar_crates(&self) { hygiene::update_dollar_crate_names(|ctxt| { let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt)); - match self.resolve_crate_root(ident).kind { - ModuleKind::Def(.., name) if let Some(name) = name => name, - _ => kw::Crate, - } + self.resolve_crate_root(ident).name().unwrap_or(kw::Crate) }); } @@ -193,7 +190,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let output_macro_rules_scope = collect_definitions(self, fragment, parent_scope); self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope); - parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion); + let module = parent_scope.module.expect_local(); + module.unexpanded_invocations.borrow_mut(self).remove(&expansion); if let Some(unexpanded_invocations) = self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion)) { @@ -523,7 +521,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { star_span: Span, ) -> Result)>, Indeterminate> { let target_trait = self.expect_module(trait_def_id); - if !target_trait.unexpanded_invocations.borrow().is_empty() { + if target_trait.has_unexpanded_invocations() { return Err(Indeterminate); } // FIXME: Instead of waiting try generating all trait methods, and pruning @@ -1183,7 +1181,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Silence `unused_imports` on the fallback import as well. self.get_mut().record_use(ident, fallback_binding, Used::Other); } else { - let location = match parent_scope.module.kind { + let location = match parent_scope.module.kind() { ModuleKind::Def(kind, def_id, _, name) => { if let Some(name) = name { format!("{} `{name}`", kind.descr(def_id))