Skip to content

Commit ab834e5

Browse files
committed
resolve: Refactor obtaining Module from its DefId
The `Option<Module>` version is supported for the case where we don't know whether the `DefId` refers to a module or not. Non-local traits and enums are also correctly found now.
1 parent a802188 commit ab834e5

File tree

6 files changed

+76
-78
lines changed

6 files changed

+76
-78
lines changed

compiler/rustc_resolve/src/build_reduced_graph.rs

+66-66
Original file line numberDiff line numberDiff line change
@@ -93,59 +93,76 @@ impl<'a> Resolver<'a> {
9393
}
9494

9595
/// Walks up the tree of definitions starting at `def_id`,
96-
/// stopping at the first `DefKind::Mod` encountered
97-
fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> {
98-
let def_key = self.cstore().def_key(def_id);
99-
100-
let mut parent_id = DefId {
101-
krate: def_id.krate,
102-
index: def_key.parent.expect("failed to get parent for module"),
103-
};
104-
// The immediate parent may not be a module
105-
// (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`)
106-
// Walk up the tree until we hit a module or the crate root.
107-
while parent_id.index != CRATE_DEF_INDEX
108-
&& self.cstore().def_kind(parent_id) != DefKind::Mod
109-
{
110-
let parent_def_key = self.cstore().def_key(parent_id);
111-
parent_id.index = parent_def_key.parent.expect("failed to get parent for module");
96+
/// stopping at the first encountered module.
97+
/// Parent block modules for arbitrary def-ids are not recorded for the local crate,
98+
/// and are not preserved in metadata for foreign crates, so block modules are never
99+
/// returned by this function.
100+
///
101+
/// For the local crate ignoring block modules may be incorrect, so use this method with care.
102+
///
103+
/// For foreign crates block modules can be ignored without introducing observable differences,
104+
/// moreover they has to be ignored right now because they are not kept in metadata.
105+
/// Foreign parent modules are used for resolving names used by foreign macros with def-site
106+
/// hygiene, therefore block module ignorability relies on macros with def-site hygiene and
107+
/// block module parents being unreachable from other crates.
108+
/// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
109+
/// but they cannot use def-site hygiene, so the assumption holds
110+
/// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
111+
fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
112+
loop {
113+
match self.get_module(def_id) {
114+
Some(module) => return module,
115+
None => {
116+
def_id.index =
117+
self.def_key(def_id).parent.expect("non-root `DefId` without parent")
118+
}
119+
}
112120
}
113-
self.get_module(parent_id)
114121
}
115122

116-
pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
117-
// Cache module resolution
118-
if let Some(module) = self.module_map.get(&def_id) {
119-
return *module;
123+
pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
124+
self.get_module(def_id).expect("argument `DefId` is not a module")
125+
}
126+
127+
/// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum,
128+
/// or trait), then this function returns that module's resolver representation, otherwise it
129+
/// returns `None`.
130+
/// FIXME: `Module`s for local enums and traits are not currently found.
131+
crate fn get_module(&mut self, def_id: DefId) -> Option<Module<'a>> {
132+
if let module @ Some(..) = self.module_map.get(&def_id) {
133+
return module.copied();
120134
}
121135

122-
assert!(!def_id.is_local());
123-
let (name, parent) = if def_id.index == CRATE_DEF_INDEX {
124-
// This is the crate root
125-
(self.cstore().crate_name(def_id.krate), None)
126-
} else {
127-
let def_key = self.cstore().def_key(def_id);
128-
let name = def_key
129-
.disambiguated_data
130-
.data
131-
.get_opt_name()
132-
.expect("given a DefId that wasn't a module");
133-
134-
let parent = Some(self.nearest_parent_mod(def_id));
135-
(name, parent)
136-
};
136+
if !def_id.is_local() {
137+
let def_kind = self.cstore().def_kind(def_id);
138+
match def_kind {
139+
DefKind::Mod | DefKind::Enum | DefKind::Trait => {
140+
let def_key = self.cstore().def_key(def_id);
141+
let parent = def_key.parent.map(|index| {
142+
self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
143+
});
144+
let name = if def_id.index == CRATE_DEF_INDEX {
145+
self.cstore().crate_name(def_id.krate)
146+
} else {
147+
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
148+
};
137149

138-
// Allocate and return a new module with the information we found
139-
let module = self.arenas.new_module(
140-
parent,
141-
ModuleKind::Def(DefKind::Mod, def_id, name),
142-
self.cstore().module_expansion_untracked(def_id, &self.session),
143-
self.cstore().get_span_untracked(def_id, &self.session),
144-
// FIXME: Account for `#[no_implicit_prelude]` attributes.
145-
parent.map_or(false, |module| module.no_implicit_prelude),
146-
);
147-
self.module_map.insert(def_id, module);
148-
module
150+
let module = self.arenas.new_module(
151+
parent,
152+
ModuleKind::Def(def_kind, def_id, name),
153+
self.cstore().module_expansion_untracked(def_id, &self.session),
154+
self.cstore().get_span_untracked(def_id, &self.session),
155+
// FIXME: Account for `#[no_implicit_prelude]` attributes.
156+
parent.map_or(false, |module| module.no_implicit_prelude),
157+
);
158+
self.module_map.insert(def_id, module);
159+
Some(module)
160+
}
161+
_ => None,
162+
}
163+
} else {
164+
None
165+
}
149166
}
150167

151168
crate fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> {
@@ -162,24 +179,7 @@ impl<'a> Resolver<'a> {
162179
if let Some(id) = def_id.as_local() {
163180
self.local_macro_def_scopes[&id]
164181
} else {
165-
// This is not entirely correct - a `macro_rules!` macro may occur
166-
// inside a 'block' module:
167-
//
168-
// ```rust
169-
// const _: () = {
170-
// #[macro_export]
171-
// macro_rules! my_macro {
172-
// () => {};
173-
// }
174-
// `
175-
// We don't record this information for external crates, so
176-
// the module we compute here will be the closest 'mod' item
177-
// (not necesssarily the actual parent of the `macro_rules!`
178-
// macro). `macro_rules!` macros can't use def-site hygiene,
179-
// so this hopefully won't be a problem.
180-
//
181-
// See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508
182-
self.nearest_parent_mod(def_id)
182+
self.get_nearest_non_block_module(def_id)
183183
}
184184
}
185185

@@ -708,7 +708,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
708708
local_def_id,
709709
);
710710
self.r.extern_crate_map.insert(local_def_id, crate_id);
711-
self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
711+
self.r.expect_module(crate_id.as_def_id())
712712
};
713713

714714
let used = self.process_macro_use_imports(item, module);

compiler/rustc_resolve/src/diagnostics.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -915,8 +915,7 @@ impl<'a> Resolver<'a> {
915915
continue;
916916
}
917917
if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) {
918-
let crate_root =
919-
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
918+
let crate_root = self.expect_module(crate_id.as_def_id());
920919
suggestions.extend(self.lookup_import_candidates_from_module(
921920
lookup_ident,
922921
namespace,

compiler/rustc_resolve/src/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
799799
}
800800

801801
fn with_scope<T>(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
802-
if let Some(module) = self.r.module_map.get(&self.r.local_def_id(id).to_def_id()).copied() {
802+
if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) {
803803
// Move down in the graph.
804804
let orig_module = replace(&mut self.parent_scope.module, module);
805805
self.with_rib(ValueNS, ModuleRibKind(module), |this| {

compiler/rustc_resolve/src/lib.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -2167,9 +2167,8 @@ impl<'a> Resolver<'a> {
21672167
return self.graph_root;
21682168
}
21692169
};
2170-
let module =
2171-
self.get_module(module.def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id());
2172-
2170+
let module = self
2171+
.expect_module(module.def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id());
21732172
debug!(
21742173
"resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})",
21752174
ident,
@@ -2181,10 +2180,10 @@ impl<'a> Resolver<'a> {
21812180
}
21822181

21832182
fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> {
2184-
let mut module = self.get_module(module.nearest_parent_mod());
2183+
let mut module = self.expect_module(module.nearest_parent_mod());
21852184
while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
21862185
let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark()));
2187-
module = self.get_module(parent.nearest_parent_mod());
2186+
module = self.expect_module(parent.nearest_parent_mod());
21882187
}
21892188
module
21902189
}
@@ -3267,7 +3266,7 @@ impl<'a> Resolver<'a> {
32673266
} else {
32683267
self.crate_loader.maybe_process_path_extern(ident.name)?
32693268
};
3270-
let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
3269+
let crate_root = self.expect_module(crate_id.as_def_id());
32713270
Some(
32723271
(crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT)
32733272
.to_name_binding(self.arenas),
@@ -3308,7 +3307,7 @@ impl<'a> Resolver<'a> {
33083307
tokens: None,
33093308
}
33103309
};
3311-
let module = self.get_module(module_id);
3310+
let module = self.expect_module(module_id);
33123311
let parent_scope = &ParentScope::module(module, self);
33133312
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
33143313
Ok((path, res))

compiler/rustc_resolve/src/macros.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
240240
);
241241

242242
let parent_scope =
243-
parent_module.map_or(self.empty_module, |def_id| self.get_module(def_id));
243+
parent_module.map_or(self.empty_module, |def_id| self.expect_module(def_id));
244244
self.ast_transform_scopes.insert(expn_id, parent_scope);
245245

246246
expn_id

src/librustdoc/passes/collect_intra_doc_links.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
759759
let mut resolver = cx.resolver.borrow_mut();
760760
let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
761761
resolver.access(|resolver| {
762-
let parent_scope = &ParentScope::module(resolver.get_module(module), resolver);
762+
let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver);
763763
resolver
764764
.traits_in_scope(None, parent_scope, SyntaxContext::root(), None)
765765
.into_iter()

0 commit comments

Comments
 (0)