Skip to content

resolve: Use interior mutability for extern module map #143550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ pub trait ResolverExpand {
fn next_node_id(&mut self) -> NodeId;
fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId;

fn resolve_dollar_crates(&mut self);
fn resolve_dollar_crates(&self);
fn visit_ast_fragment_with_placeholders(
&mut self,
expn_id: LocalExpnId,
Expand Down
71 changes: 37 additions & 34 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
/// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
/// but they cannot use def-site hygiene, so the assumption holds
/// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
pub(crate) fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'ra> {
pub(crate) fn get_nearest_non_block_module(&self, mut def_id: DefId) -> Module<'ra> {
loop {
match self.get_module(def_id) {
Some(module) => return module,
Expand All @@ -94,44 +94,47 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

pub(crate) fn expect_module(&mut self, def_id: DefId) -> Module<'ra> {
pub(crate) fn expect_module(&self, def_id: DefId) -> Module<'ra> {
self.get_module(def_id).expect("argument `DefId` is not a module")
}

/// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum,
/// or trait), then this function returns that module's resolver representation, otherwise it
/// returns `None`.
pub(crate) fn get_module(&mut self, def_id: DefId) -> Option<Module<'ra>> {
if let module @ Some(..) = self.module_map.get(&def_id) {
return module.copied();
}
pub(crate) fn get_module(&self, def_id: DefId) -> Option<Module<'ra>> {
match def_id.as_local() {
Some(local_def_id) => self.local_module_map.get(&local_def_id).copied(),
None => {
if let module @ Some(..) = self.extern_module_map.borrow().get(&def_id) {
return module.copied();
}

if !def_id.is_local() {
// Query `def_kind` is not used because query system overhead is too expensive here.
let def_kind = self.cstore().def_kind_untracked(def_id);
if def_kind.is_module_like() {
let parent = self
.tcx
.opt_parent(def_id)
.map(|parent_id| self.get_nearest_non_block_module(parent_id));
// Query `expn_that_defined` is not used because
// hashing spans in its result is expensive.
let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
return Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
expn_id,
self.def_span(def_id),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.is_some_and(|module| module.no_implicit_prelude),
));
// Query `def_kind` is not used because query system overhead is too expensive here.
let def_kind = self.cstore().def_kind_untracked(def_id);
if def_kind.is_module_like() {
let parent = self
.tcx
.opt_parent(def_id)
.map(|parent_id| self.get_nearest_non_block_module(parent_id));
// Query `expn_that_defined` is not used because
// hashing spans in its result is expensive.
let expn_id = self.cstore().expn_that_defined_untracked(def_id, self.tcx.sess);
return Some(self.new_extern_module(
parent,
ModuleKind::Def(def_kind, def_id, Some(self.tcx.item_name(def_id))),
expn_id,
self.def_span(def_id),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.is_some_and(|module| module.no_implicit_prelude),
));
}

None
}
}

None
}

pub(crate) fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'ra> {
pub(crate) fn expn_def_scope(&self, expn_id: ExpnId) -> Module<'ra> {
match expn_id.expn_data().macro_def_id {
Some(def_id) => self.macro_def_scope(def_id),
None => expn_id
Expand All @@ -141,7 +144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

pub(crate) fn macro_def_scope(&mut self, def_id: DefId) -> Module<'ra> {
pub(crate) fn macro_def_scope(&self, def_id: DefId) -> Module<'ra> {
if let Some(id) = def_id.as_local() {
self.local_macro_def_scopes[&id]
} else {
Expand Down Expand Up @@ -403,7 +406,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
self.r.field_visibility_spans.insert(def_id, field_vis);
}

fn block_needs_anonymous_module(&mut self, block: &Block) -> bool {
fn block_needs_anonymous_module(&self, block: &Block) -> bool {
// If any statements are items, we need to create an anonymous module
block
.stmts
Expand Down Expand Up @@ -758,7 +761,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind {
self.r.mods_with_parse_errors.insert(def_id);
}
self.parent_scope.module = self.r.new_module(
self.parent_scope.module = self.r.new_local_module(
Some(parent),
ModuleKind::Def(def_kind, def_id, Some(ident.name)),
expansion.to_expn_id(),
Expand Down Expand Up @@ -790,7 +793,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => {
self.r.define(parent, ident, TypeNS, res, vis, sp, expansion);

self.parent_scope.module = self.r.new_module(
self.parent_scope.module = self.r.new_local_module(
Some(parent),
ModuleKind::Def(def_kind, def_id, Some(ident.name)),
expansion.to_expn_id(),
Expand Down Expand Up @@ -986,7 +989,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
let parent = self.parent_scope.module;
let expansion = self.parent_scope.expansion;
if self.block_needs_anonymous_module(block) {
let module = self.r.new_module(
let module = self.r.new_local_module(
Some(parent),
ModuleKind::Block,
expansion.to_expn_id(),
Expand Down Expand Up @@ -1118,7 +1121,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}

/// Returns `true` if this attribute list contains `macro_use`.
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
fn contains_macro_use(&self, attrs: &[ast::Attribute]) -> bool {
for attr in attrs {
if attr.has_name(sym::macro_escape) {
let inner_attribute = matches!(attr.style, ast::AttrStyle::Inner);
Expand Down
46 changes: 27 additions & 19 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2150,7 +2150,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

pub(crate) fn find_similarly_named_module_or_crate(
&mut self,
&self,
ident: Symbol,
current_module: Module<'ra>,
) -> Option<Symbol> {
Expand All @@ -2159,7 +2159,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
.keys()
.map(|ident| ident.name)
.chain(
self.module_map
self.local_module_map
.iter()
.filter(|(_, module)| {
current_module.is_ancestor_of(**module) && current_module != **module
})
.flat_map(|(_, module)| module.kind.name()),
)
.chain(
self.extern_module_map
.borrow()
.iter()
.filter(|(_, module)| {
current_module.is_ancestor_of(**module) && current_module != **module
Expand Down Expand Up @@ -2435,7 +2444,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

fn undeclared_module_suggest_declare(
&mut self,
&self,
ident: Ident,
path: std::path::PathBuf,
) -> Option<(Vec<(Span, String)>, String, Applicability)> {
Expand All @@ -2450,7 +2459,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
))
}

fn undeclared_module_exists(&mut self, ident: Ident) -> Option<std::path::PathBuf> {
fn undeclared_module_exists(&self, ident: Ident) -> Option<std::path::PathBuf> {
let map = self.tcx.sess.source_map();

let src = map.span_to_filename(ident.span).into_local_path()?;
Expand Down Expand Up @@ -2809,24 +2818,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
return cached;
}
visited.insert(parent_module, false);
let res = r.module_map.get(&parent_module).is_some_and(|m| {
for importer in m.glob_importers.borrow().iter() {
if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id()
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 next_parent_module == module
|| comes_from_same_module_for_glob(
r,
next_parent_module,
module,
visited,
)
{
return true;
}
res = true;
break;
}
}
false
});
}
visited.insert(parent_module, res);
res
}
Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_resolve/src/effective_visibilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ pub(crate) struct EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
}

impl Resolver<'_, '_> {
fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
fn nearest_normal_mod(&self, def_id: LocalDefId) -> LocalDefId {
self.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
}

fn private_vis_import(&mut self, binding: NameBinding<'_>) -> Visibility {
fn private_vis_import(&self, binding: NameBinding<'_>) -> Visibility {
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
Visibility::Restricted(
import
Expand All @@ -52,7 +52,7 @@ impl Resolver<'_, '_> {
)
}

fn private_vis_def(&mut self, def_id: LocalDefId) -> Visibility {
fn private_vis_def(&self, def_id: LocalDefId) -> Visibility {
// For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
let normal_mod_id = self.nearest_normal_mod(def_id);
if normal_mod_id == def_id {
Expand Down Expand Up @@ -113,8 +113,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
/// Update effective visibilities of bindings in the given module,
/// including their whole reexport chains.
fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
assert!(self.r.module_map.contains_key(&module_id.to_def_id()));
let module = self.r.get_module(module_id.to_def_id()).unwrap();
let module = self.r.expect_module(module_id.to_def_id());
let resolutions = self.r.resolutions(module);

for (_, name_resolution) in resolutions.borrow().iter() {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

fn hygienic_lexical_parent(
&mut self,
&self,
module: Module<'ra>,
ctxt: &mut SyntaxContext,
derive_fallback_lint_id: Option<NodeId>,
Expand Down Expand Up @@ -841,7 +841,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if ns == TypeNS {
if ident.name == kw::Crate || ident.name == kw::DollarCrate {
let module = self.resolve_crate_root(ident);
return Ok(self.module_self_bindings[&module]);
return Ok(module.self_binding.unwrap());
} else if ident.name == kw::Super || ident.name == kw::SelfLower {
// FIXME: Implement these with renaming requirements so that e.g.
// `use super;` doesn't work, but `use super as name;` does.
Expand Down Expand Up @@ -885,7 +885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
);
}

let check_usable = |this: &mut Self, binding: NameBinding<'ra>| {
let check_usable = |this: &Self, binding: NameBinding<'ra>| {
let usable = this.is_accessible_from(binding.vis, parent_scope.module);
if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
f: F,
) -> T
where
F: FnOnce(&mut Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
F: FnOnce(&Resolver<'ra, 'tcx>, &mut NameResolution<'ra>) -> T,
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2491,7 +2491,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

/// Searches the current set of local scopes for labels. Returns the `NodeId` of the resolved
/// label and reports an error if the label is not found or is unreachable.
fn resolve_label(&mut self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
fn resolve_label(&self, mut label: Ident) -> Result<(NodeId, Span), ResolutionError<'ra>> {
let mut suggestion = None;

for i in (0..self.label_ribs.len()).rev() {
Expand Down
Loading
Loading