@@ -93,59 +93,76 @@ impl<'a> Resolver<'a> {
93
93
}
94
94
95
95
/// 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
+ }
112
120
}
113
- self . get_module ( parent_id)
114
121
}
115
122
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 ( ) ;
120
134
}
121
135
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
+ } ;
137
149
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
+ }
149
166
}
150
167
151
168
crate fn expn_def_scope ( & mut self , expn_id : ExpnId ) -> Module < ' a > {
@@ -162,24 +179,7 @@ impl<'a> Resolver<'a> {
162
179
if let Some ( id) = def_id. as_local ( ) {
163
180
self . local_macro_def_scopes [ & id]
164
181
} 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)
183
183
}
184
184
}
185
185
@@ -708,7 +708,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
708
708
local_def_id,
709
709
) ;
710
710
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 ( ) )
712
712
} ;
713
713
714
714
let used = self . process_macro_use_imports ( item, module) ;
0 commit comments