@@ -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) ;
0 commit comments