1
Fork 0

Rollup merge of #77984 - Aaron1011:fix/macro-mod-weird-parent, r=petrochenkov

Compute proper module parent during resolution

Fixes #75982

The direct parent of a module may not be a module
(e.g. `const _: () =  { #[path = "foo.rs"] mod foo; };`).

To find the parent of a module for purposes of resolution, we need to
walk up the tree until we hit a module or a crate root.
This commit is contained in:
Yuki Okushi 2020-10-25 18:43:37 +09:00 committed by GitHub
commit 569d29d55c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 7 deletions

View file

@ -95,6 +95,27 @@ impl<'a> Resolver<'a> {
}
}
/// Walks up the tree of definitions starting at `def_id`,
/// stopping at the first `DefKind::Mod` encountered
fn nearest_mod_parent(&mut self, def_id: DefId) -> Module<'a> {
let def_key = self.cstore().def_key(def_id);
let mut parent_id = DefId {
krate: def_id.krate,
index: def_key.parent.expect("failed to get parent for module"),
};
// The immediate parent may not be a module
// (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`)
// Walk up the tree until we hit a module or the crate root.
while parent_id.index != CRATE_DEF_INDEX
&& self.cstore().def_kind(parent_id) != DefKind::Mod
{
let parent_def_key = self.cstore().def_key(parent_id);
parent_id.index = parent_def_key.parent.expect("failed to get parent for module");
}
self.get_module(parent_id)
}
crate fn get_module(&mut self, def_id: DefId) -> Module<'a> {
// If this is a local module, it will be in `module_map`, no need to recalculate it.
if let Some(def_id) = def_id.as_local() {
@ -116,11 +137,8 @@ impl<'a> Resolver<'a> {
.data
.get_opt_name()
.expect("given a DefId that wasn't a module");
// This unwrap is safe since we know this isn't the root
let parent = Some(self.get_module(DefId {
index: def_key.parent.expect("failed to get parent for module"),
..def_id
}));
let parent = Some(self.nearest_mod_parent(def_id));
(name, parent)
};
@ -145,8 +163,24 @@ impl<'a> Resolver<'a> {
if let Some(id) = def_id.as_local() {
self.local_macro_def_scopes[&id]
} else {
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
self.get_module(module_def_id)
// This is not entirely correct - a `macro_rules!` macro may occur
// inside a 'block' module:
//
// ```rust
// const _: () = {
// #[macro_export]
// macro_rules! my_macro {
// () => {};
// }
// `
// We don't record this information for external crates, so
// the module we compute here will be the closest 'mod' item
// (not necesssarily the actual parent of the `macro_rules!`
// macro). `macro_rules!` macros can't use def-site hygiene,
// so this hopefully won't be a problem.
//
// See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508
self.nearest_mod_parent(def_id)
}
}