diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-09 13:54:02 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-09 13:54:02 +0100 |
commit | 40f91341595508833d39eb6d97e4ec2ac7f685cb (patch) | |
tree | 3022252410b228efb6501e9e8ff6268c910c87cb /crates/ra_hir/src/nameres/collector.rs | |
parent | 734a43e95afc97773c234956a95b78caed88f2a3 (diff) |
Make macro scope a real name scope
Fix some details about module scoping
Diffstat (limited to 'crates/ra_hir/src/nameres/collector.rs')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 178 |
1 files changed, 95 insertions, 83 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 09cda7656..03fbbd33f 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -5,14 +5,13 @@ use test_utils::tested_by; | |||
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | either::Either, | ||
9 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, | 8 | ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, |
10 | name::MACRO_RULES, | 9 | name::MACRO_RULES, |
11 | nameres::{ | 10 | nameres::{ |
12 | diagnostics::DefDiagnostic, | 11 | diagnostics::DefDiagnostic, |
13 | mod_resolution::{resolve_submodule, ParentModule}, | 12 | mod_resolution::{resolve_submodule, ParentModule}, |
14 | raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, | 13 | raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, |
15 | ReachedFixedPoint, Resolution, ResolveMode, | 14 | Resolution, ResolveMode, |
16 | }, | 15 | }, |
17 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, | 16 | AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, |
18 | Struct, Trait, TypeAlias, Union, | 17 | Struct, Trait, TypeAlias, Union, |
@@ -123,30 +122,51 @@ where | |||
123 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 122 | let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
124 | // show unresolved imports in completion, etc | 123 | // show unresolved imports in completion, etc |
125 | for (module_id, import, import_data) in unresolved_imports { | 124 | for (module_id, import, import_data) in unresolved_imports { |
126 | self.record_resolved_import(module_id, Either::A(PerNs::none()), import, &import_data) | 125 | self.record_resolved_import(module_id, PerNs::none(), import, &import_data) |
127 | } | 126 | } |
128 | } | 127 | } |
129 | 128 | ||
129 | /// Define a macro with `macro_rules`. | ||
130 | /// | ||
131 | /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`, | ||
132 | /// then it is also defined in the root module scope. | ||
133 | /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition. | ||
134 | /// | ||
135 | /// It is surprising that the macro will never be in the current module scope. | ||
136 | /// These code fails with "unresolved import/macro", | ||
137 | /// ```rust,compile_fail | ||
138 | /// mod m { macro_rules! foo { () => {} } } | ||
139 | /// use m::foo as bar; | ||
140 | /// ``` | ||
141 | /// | ||
142 | /// ```rust,compile_fail | ||
143 | /// macro_rules! foo { () => {} } | ||
144 | /// self::foo!(); | ||
145 | /// crate::foo!(); | ||
146 | /// ``` | ||
147 | /// | ||
148 | /// Well, this code compiles, bacause the plain path `foo` in `use` is searched | ||
149 | /// in the legacy textual scope only. | ||
150 | /// ```rust | ||
151 | /// macro_rules! foo { () => {} } | ||
152 | /// use foo as bar; | ||
153 | /// ``` | ||
130 | fn define_macro( | 154 | fn define_macro( |
131 | &mut self, | 155 | &mut self, |
132 | module_id: CrateModuleId, | 156 | module_id: CrateModuleId, |
133 | name: Name, | 157 | name: Name, |
134 | macro_id: MacroDefId, | 158 | macro_: MacroDef, |
135 | export: bool, | 159 | export: bool, |
136 | ) { | 160 | ) { |
137 | let def = Either::B(MacroDef { id: macro_id }); | 161 | // Textual scoping |
162 | self.define_legacy_macro(module_id, name.clone(), macro_); | ||
138 | 163 | ||
164 | // Module scoping | ||
139 | // In Rust, `#[macro_export]` macros are unconditionally visible at the | 165 | // In Rust, `#[macro_export]` macros are unconditionally visible at the |
140 | // crate root, even if the parent modules is **not** visible. | 166 | // crate root, even if the parent modules is **not** visible. |
141 | if export { | 167 | if export { |
142 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 168 | self.update(self.def_map.root, None, &[(name.clone(), Resolution::from_macro(macro_))]); |
143 | |||
144 | // Exported macros are collected in crate level ready for | ||
145 | // glob import with `#[macro_use]`. | ||
146 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
147 | } | 169 | } |
148 | self.update(module_id, None, &[(name.clone(), def)]); | ||
149 | self.define_legacy_macro(module_id, name.clone(), macro_id); | ||
150 | } | 170 | } |
151 | 171 | ||
152 | /// Define a legacy textual scoped macro in module | 172 | /// Define a legacy textual scoped macro in module |
@@ -156,14 +176,12 @@ where | |||
156 | /// the definition of current module. | 176 | /// the definition of current module. |
157 | /// And also, `macro_use` on a module will import all legacy macros visable inside to | 177 | /// And also, `macro_use` on a module will import all legacy macros visable inside to |
158 | /// current legacy scope, with possible shadowing. | 178 | /// current legacy scope, with possible shadowing. |
159 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | 179 | fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) { |
160 | // Always shadowing | 180 | // Always shadowing |
161 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id }); | 181 | self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); |
162 | } | 182 | } |
163 | 183 | ||
164 | /// Import macros from `#[macro_use] extern crate`. | 184 | /// Import macros from `#[macro_use] extern crate`. |
165 | /// | ||
166 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
167 | fn import_macros_from_extern_crate( | 185 | fn import_macros_from_extern_crate( |
168 | &mut self, | 186 | &mut self, |
169 | current_module_id: CrateModuleId, | 187 | current_module_id: CrateModuleId, |
@@ -184,14 +202,20 @@ where | |||
184 | 202 | ||
185 | if let Some(ModuleDef::Module(m)) = res.take_types() { | 203 | if let Some(ModuleDef::Module(m)) = res.take_types() { |
186 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | 204 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); |
187 | self.import_all_macros_exported(current_module_id, m); | 205 | self.import_all_macros_exported(current_module_id, m.krate); |
188 | } | 206 | } |
189 | } | 207 | } |
190 | 208 | ||
191 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) { | 209 | /// Import all exported macros from another crate |
192 | let item_map = self.db.crate_def_map(module.krate); | 210 | /// |
193 | for (name, ¯o_id) in &item_map.exported_macros { | 211 | /// Exported macros are just all macros in the root module scope. |
194 | self.define_legacy_macro(current_module_id, name.clone(), macro_id); | 212 | /// Note that it contains not only all `#[macro_export]` macros, but also all aliases |
213 | /// created by `use` in the root module, ignoring the visibility of `use`. | ||
214 | fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) { | ||
215 | let def_map = self.db.crate_def_map(krate); | ||
216 | for (name, def) in def_map[def_map.root].scope.macros() { | ||
217 | // `macro_use` only bring things into legacy scope. | ||
218 | self.define_legacy_macro(current_module_id, name.clone(), def); | ||
195 | } | 219 | } |
196 | } | 220 | } |
197 | 221 | ||
@@ -219,7 +243,7 @@ where | |||
219 | &self, | 243 | &self, |
220 | module_id: CrateModuleId, | 244 | module_id: CrateModuleId, |
221 | import: &raw::ImportData, | 245 | import: &raw::ImportData, |
222 | ) -> (ItemOrMacro, ReachedFixedPoint) { | 246 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { |
223 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); | 247 | log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); |
224 | if import.is_extern_crate { | 248 | if import.is_extern_crate { |
225 | let res = self.def_map.resolve_name_in_extern_prelude( | 249 | let res = self.def_map.resolve_name_in_extern_prelude( |
@@ -228,7 +252,7 @@ where | |||
228 | .as_ident() | 252 | .as_ident() |
229 | .expect("extern crate should have been desugared to one-element path"), | 253 | .expect("extern crate should have been desugared to one-element path"), |
230 | ); | 254 | ); |
231 | (Either::A(res), ReachedFixedPoint::Yes) | 255 | (res, ReachedFixedPoint::Yes) |
232 | } else { | 256 | } else { |
233 | let res = self.def_map.resolve_path_fp_with_macro( | 257 | let res = self.def_map.resolve_path_fp_with_macro( |
234 | self.db, | 258 | self.db, |
@@ -244,13 +268,13 @@ where | |||
244 | fn record_resolved_import( | 268 | fn record_resolved_import( |
245 | &mut self, | 269 | &mut self, |
246 | module_id: CrateModuleId, | 270 | module_id: CrateModuleId, |
247 | def: ItemOrMacro, | 271 | def: PerNs<ModuleDef>, |
248 | import_id: raw::ImportId, | 272 | import_id: raw::ImportId, |
249 | import: &raw::ImportData, | 273 | import: &raw::ImportData, |
250 | ) { | 274 | ) { |
251 | if import.is_glob { | 275 | if import.is_glob { |
252 | log::debug!("glob import: {:?}", import); | 276 | log::debug!("glob import: {:?}", import); |
253 | match def.a().and_then(|item| item.take_types()) { | 277 | match def.take_types() { |
254 | Some(ModuleDef::Module(m)) => { | 278 | Some(ModuleDef::Module(m)) => { |
255 | if import.is_prelude { | 279 | if import.is_prelude { |
256 | tested_by!(std_prelude); | 280 | tested_by!(std_prelude); |
@@ -260,30 +284,29 @@ where | |||
260 | // glob import from other crate => we can just import everything once | 284 | // glob import from other crate => we can just import everything once |
261 | let item_map = self.db.crate_def_map(m.krate); | 285 | let item_map = self.db.crate_def_map(m.krate); |
262 | let scope = &item_map[m.module_id].scope; | 286 | let scope = &item_map[m.module_id].scope; |
287 | |||
288 | // Module scoped macros is included | ||
263 | let items = scope | 289 | let items = scope |
264 | .items | 290 | .items |
265 | .iter() | 291 | .iter() |
266 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 292 | .map(|(name, res)| (name.clone(), res.clone())) |
267 | let macros = | 293 | .collect::<Vec<_>>(); |
268 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
269 | 294 | ||
270 | let all = items.chain(macros).collect::<Vec<_>>(); | 295 | self.update(module_id, Some(import_id), &items); |
271 | self.update(module_id, Some(import_id), &all); | ||
272 | } else { | 296 | } else { |
273 | // glob import from same crate => we do an initial | 297 | // glob import from same crate => we do an initial |
274 | // import, and then need to propagate any further | 298 | // import, and then need to propagate any further |
275 | // additions | 299 | // additions |
276 | let scope = &self.def_map[m.module_id].scope; | 300 | let scope = &self.def_map[m.module_id].scope; |
301 | |||
302 | // Module scoped macros is included | ||
277 | let items = scope | 303 | let items = scope |
278 | .items | 304 | .items |
279 | .iter() | 305 | .iter() |
280 | .map(|(name, res)| (name.clone(), Either::A(res.clone()))); | 306 | .map(|(name, res)| (name.clone(), res.clone())) |
281 | let macros = | 307 | .collect::<Vec<_>>(); |
282 | scope.macros.iter().map(|(name, res)| (name.clone(), Either::B(*res))); | ||
283 | 308 | ||
284 | let all = items.chain(macros).collect::<Vec<_>>(); | 309 | self.update(module_id, Some(import_id), &items); |
285 | |||
286 | self.update(module_id, Some(import_id), &all); | ||
287 | // record the glob import in case we add further items | 310 | // record the glob import in case we add further items |
288 | self.glob_imports | 311 | self.glob_imports |
289 | .entry(m.module_id) | 312 | .entry(m.module_id) |
@@ -303,7 +326,7 @@ where | |||
303 | import: Some(import_id), | 326 | import: Some(import_id), |
304 | }; | 327 | }; |
305 | let name = variant.name(self.db)?; | 328 | let name = variant.name(self.db)?; |
306 | Some((name, Either::A(res))) | 329 | Some((name, res)) |
307 | }) | 330 | }) |
308 | .collect::<Vec<_>>(); | 331 | .collect::<Vec<_>>(); |
309 | self.update(module_id, Some(import_id), &resolutions); | 332 | self.update(module_id, Some(import_id), &resolutions); |
@@ -323,18 +346,12 @@ where | |||
323 | 346 | ||
324 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 | 347 | // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 |
325 | if import.is_extern_crate && module_id == self.def_map.root { | 348 | if import.is_extern_crate && module_id == self.def_map.root { |
326 | if let Some(def) = def.a().and_then(|item| item.take_types()) { | 349 | if let Some(def) = def.take_types() { |
327 | self.def_map.extern_prelude.insert(name.clone(), def); | 350 | self.def_map.extern_prelude.insert(name.clone(), def); |
328 | } | 351 | } |
329 | } | 352 | } |
330 | 353 | ||
331 | let resolution = match def { | 354 | let resolution = Resolution { def, import: Some(import_id) }; |
332 | Either::A(item) => { | ||
333 | Either::A(Resolution { def: item, import: Some(import_id) }) | ||
334 | } | ||
335 | Either::B(macro_) => Either::B(macro_), | ||
336 | }; | ||
337 | |||
338 | self.update(module_id, Some(import_id), &[(name, resolution)]); | 355 | self.update(module_id, Some(import_id), &[(name, resolution)]); |
339 | } | 356 | } |
340 | None => tested_by!(bogus_paths), | 357 | None => tested_by!(bogus_paths), |
@@ -346,7 +363,7 @@ where | |||
346 | &mut self, | 363 | &mut self, |
347 | module_id: CrateModuleId, | 364 | module_id: CrateModuleId, |
348 | import: Option<raw::ImportId>, | 365 | import: Option<raw::ImportId>, |
349 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 366 | resolutions: &[(Name, Resolution)], |
350 | ) { | 367 | ) { |
351 | self.update_recursive(module_id, import, resolutions, 0) | 368 | self.update_recursive(module_id, import, resolutions, 0) |
352 | } | 369 | } |
@@ -355,7 +372,7 @@ where | |||
355 | &mut self, | 372 | &mut self, |
356 | module_id: CrateModuleId, | 373 | module_id: CrateModuleId, |
357 | import: Option<raw::ImportId>, | 374 | import: Option<raw::ImportId>, |
358 | resolutions: &[(Name, Either<Resolution, MacroDef>)], | 375 | resolutions: &[(Name, Resolution)], |
359 | depth: usize, | 376 | depth: usize, |
360 | ) { | 377 | ) { |
361 | if depth > 100 { | 378 | if depth > 100 { |
@@ -365,35 +382,30 @@ where | |||
365 | let module_items = &mut self.def_map.modules[module_id].scope; | 382 | let module_items = &mut self.def_map.modules[module_id].scope; |
366 | let mut changed = false; | 383 | let mut changed = false; |
367 | for (name, res) in resolutions { | 384 | for (name, res) in resolutions { |
368 | match res { | 385 | let existing = module_items.items.entry(name.clone()).or_default(); |
369 | // item | ||
370 | Either::A(res) => { | ||
371 | let existing = module_items.items.entry(name.clone()).or_default(); | ||
372 | |||
373 | if existing.def.types.is_none() && res.def.types.is_some() { | ||
374 | existing.def.types = res.def.types; | ||
375 | existing.import = import.or(res.import); | ||
376 | changed = true; | ||
377 | } | ||
378 | if existing.def.values.is_none() && res.def.values.is_some() { | ||
379 | existing.def.values = res.def.values; | ||
380 | existing.import = import.or(res.import); | ||
381 | changed = true; | ||
382 | } | ||
383 | 386 | ||
384 | if existing.def.is_none() | 387 | if existing.def.types.is_none() && res.def.types.is_some() { |
385 | && res.def.is_none() | 388 | existing.def.types = res.def.types; |
386 | && existing.import.is_none() | 389 | existing.import = import.or(res.import); |
387 | && res.import.is_some() | 390 | changed = true; |
388 | { | 391 | } |
389 | existing.import = res.import; | 392 | if existing.def.values.is_none() && res.def.values.is_some() { |
390 | } | 393 | existing.def.values = res.def.values; |
391 | } | 394 | existing.import = import.or(res.import); |
392 | // macro | 395 | changed = true; |
393 | Either::B(res) => { | 396 | } |
394 | // Always shadowing | 397 | if existing.def.macros.is_none() && res.def.macros.is_some() { |
395 | module_items.macros.insert(name.clone(), *res); | 398 | existing.def.macros = res.def.macros; |
396 | } | 399 | existing.import = import.or(res.import); |
400 | changed = true; | ||
401 | } | ||
402 | |||
403 | if existing.def.is_none() | ||
404 | && res.def.is_none() | ||
405 | && existing.import.is_none() | ||
406 | && res.import.is_some() | ||
407 | { | ||
408 | existing.import = res.import; | ||
397 | } | 409 | } |
398 | } | 410 | } |
399 | 411 | ||
@@ -425,7 +437,7 @@ where | |||
425 | path, | 437 | path, |
426 | ); | 438 | ); |
427 | 439 | ||
428 | if let Some(def) = resolved_res.resolved_def.b() { | 440 | if let Some(def) = resolved_res.resolved_def.get_macros() { |
429 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); | 441 | let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); |
430 | resolved.push((*module_id, call_id, def.id)); | 442 | resolved.push((*module_id, call_id, def.id)); |
431 | res = ReachedFixedPoint::No; | 443 | res = ReachedFixedPoint::No; |
@@ -528,7 +540,7 @@ where | |||
528 | if let Some(prelude_module) = self.def_collector.def_map.prelude { | 540 | if let Some(prelude_module) = self.def_collector.def_map.prelude { |
529 | if prelude_module.krate != self.def_collector.def_map.krate { | 541 | if prelude_module.krate != self.def_collector.def_map.krate { |
530 | tested_by!(prelude_is_macro_use); | 542 | tested_by!(prelude_is_macro_use); |
531 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module); | 543 | self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); |
532 | } | 544 | } |
533 | } | 545 | } |
534 | 546 | ||
@@ -636,7 +648,7 @@ where | |||
636 | ), | 648 | ), |
637 | import: None, | 649 | import: None, |
638 | }; | 650 | }; |
639 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]); | 651 | self.def_collector.update(self.module_id, None, &[(name, resolution)]); |
640 | res | 652 | res |
641 | } | 653 | } |
642 | 654 | ||
@@ -667,7 +679,7 @@ where | |||
667 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), | 679 | raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), |
668 | }; | 680 | }; |
669 | let resolution = Resolution { def, import: None }; | 681 | let resolution = Resolution { def, import: None }; |
670 | self.def_collector.update(self.module_id, None, &[(name, Either::A(resolution))]) | 682 | self.def_collector.update(self.module_id, None, &[(name, resolution)]) |
671 | } | 683 | } |
672 | 684 | ||
673 | fn collect_macro(&mut self, mac: &raw::MacroData) { | 685 | fn collect_macro(&mut self, mac: &raw::MacroData) { |
@@ -675,7 +687,8 @@ where | |||
675 | if is_macro_rules(&mac.path) { | 687 | if is_macro_rules(&mac.path) { |
676 | if let Some(name) = &mac.name { | 688 | if let Some(name) = &mac.name { |
677 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); | 689 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); |
678 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export) | 690 | let macro_ = MacroDef { id: macro_id }; |
691 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); | ||
679 | } | 692 | } |
680 | return; | 693 | return; |
681 | } | 694 | } |
@@ -706,7 +719,7 @@ where | |||
706 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { | 719 | fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { |
707 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); | 720 | let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); |
708 | for (name, macro_) in macros { | 721 | for (name, macro_) in macros { |
709 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id); | 722 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
710 | } | 723 | } |
711 | } | 724 | } |
712 | } | 725 | } |
@@ -758,7 +771,6 @@ mod tests { | |||
758 | root, | 771 | root, |
759 | modules, | 772 | modules, |
760 | poison_macros: FxHashSet::default(), | 773 | poison_macros: FxHashSet::default(), |
761 | exported_macros: FxHashMap::default(), | ||
762 | diagnostics: Vec::new(), | 774 | diagnostics: Vec::new(), |
763 | } | 775 | } |
764 | }; | 776 | }; |