diff options
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 178 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/per_ns.rs | 59 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 46 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 119 |
4 files changed, 262 insertions, 140 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 | }; |
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs index c40a3ff9d..d07cc08f4 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -1,78 +1,87 @@ | |||
1 | use crate::MacroDef; | ||
2 | |||
1 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 3 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
2 | pub enum Namespace { | 4 | pub enum Namespace { |
3 | Types, | 5 | Types, |
4 | Values, | 6 | Values, |
7 | // Note that only type inference uses this enum, and it doesn't care about macros. | ||
8 | // Macro, | ||
5 | } | 9 | } |
6 | 10 | ||
7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
8 | pub struct PerNs<T> { | 12 | pub struct PerNs<T> { |
9 | pub types: Option<T>, | 13 | pub types: Option<T>, |
10 | pub values: Option<T>, | 14 | pub values: Option<T>, |
15 | /// Since macros has different type, many methods simply ignore it. | ||
16 | /// We can only use special method like `get_macros` to access it. | ||
17 | pub macros: Option<MacroDef>, | ||
11 | } | 18 | } |
12 | 19 | ||
13 | impl<T> Default for PerNs<T> { | 20 | impl<T> Default for PerNs<T> { |
14 | fn default() -> Self { | 21 | fn default() -> Self { |
15 | PerNs { types: None, values: None } | 22 | PerNs { types: None, values: None, macros: None } |
16 | } | 23 | } |
17 | } | 24 | } |
18 | 25 | ||
19 | impl<T> PerNs<T> { | 26 | impl<T> PerNs<T> { |
20 | pub fn none() -> PerNs<T> { | 27 | pub fn none() -> PerNs<T> { |
21 | PerNs { types: None, values: None } | 28 | PerNs { types: None, values: None, macros: None } |
22 | } | 29 | } |
23 | 30 | ||
24 | pub fn values(t: T) -> PerNs<T> { | 31 | pub fn values(t: T) -> PerNs<T> { |
25 | PerNs { types: None, values: Some(t) } | 32 | PerNs { types: None, values: Some(t), macros: None } |
26 | } | 33 | } |
27 | 34 | ||
28 | pub fn types(t: T) -> PerNs<T> { | 35 | pub fn types(t: T) -> PerNs<T> { |
29 | PerNs { types: Some(t), values: None } | 36 | PerNs { types: Some(t), values: None, macros: None } |
30 | } | 37 | } |
31 | 38 | ||
32 | pub fn both(types: T, values: T) -> PerNs<T> { | 39 | pub fn both(types: T, values: T) -> PerNs<T> { |
33 | PerNs { types: Some(types), values: Some(values) } | 40 | PerNs { types: Some(types), values: Some(values), macros: None } |
34 | } | 41 | } |
35 | 42 | ||
36 | pub fn is_none(&self) -> bool { | 43 | pub fn macros(macro_: MacroDef) -> PerNs<T> { |
37 | self.types.is_none() && self.values.is_none() | 44 | PerNs { types: None, values: None, macros: Some(macro_) } |
38 | } | 45 | } |
39 | 46 | ||
40 | pub fn is_both(&self) -> bool { | 47 | pub fn is_none(&self) -> bool { |
41 | self.types.is_some() && self.values.is_some() | 48 | self.types.is_none() && self.values.is_none() && self.macros.is_none() |
42 | } | 49 | } |
43 | 50 | ||
44 | pub fn take(self, namespace: Namespace) -> Option<T> { | 51 | pub fn is_all(&self) -> bool { |
45 | match namespace { | 52 | self.types.is_some() && self.values.is_some() && self.macros.is_some() |
46 | Namespace::Types => self.types, | ||
47 | Namespace::Values => self.values, | ||
48 | } | ||
49 | } | 53 | } |
50 | 54 | ||
51 | pub fn take_types(self) -> Option<T> { | 55 | pub fn take_types(self) -> Option<T> { |
52 | self.take(Namespace::Types) | 56 | self.types |
53 | } | 57 | } |
54 | 58 | ||
55 | pub fn take_values(self) -> Option<T> { | 59 | pub fn take_values(self) -> Option<T> { |
56 | self.take(Namespace::Values) | 60 | self.values |
57 | } | 61 | } |
58 | 62 | ||
59 | pub fn get(&self, namespace: Namespace) -> Option<&T> { | 63 | pub fn get_macros(&self) -> Option<MacroDef> { |
60 | self.as_ref().take(namespace) | 64 | self.macros |
61 | } | 65 | } |
62 | 66 | ||
63 | pub fn as_ref(&self) -> PerNs<&T> { | 67 | pub fn only_macros(&self) -> PerNs<T> { |
64 | PerNs { types: self.types.as_ref(), values: self.values.as_ref() } | 68 | PerNs { types: None, values: None, macros: self.macros } |
65 | } | 69 | } |
66 | 70 | ||
67 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | 71 | pub fn as_ref(&self) -> PerNs<&T> { |
68 | PerNs { types: self.types.or(other.types), values: self.values.or(other.values) } | 72 | PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros } |
69 | } | 73 | } |
70 | 74 | ||
71 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | 75 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { |
72 | PerNs { types: self.types.and_then(&f), values: self.values.and_then(&f) } | 76 | PerNs { |
77 | types: self.types.or(other.types), | ||
78 | values: self.values.or(other.values), | ||
79 | macros: self.macros.or(other.macros), | ||
80 | } | ||
73 | } | 81 | } |
74 | 82 | ||
83 | /// Map types and values. Leave macros unchanged. | ||
75 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | 84 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { |
76 | PerNs { types: self.types.map(&f), values: self.values.map(&f) } | 85 | PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros } |
77 | } | 86 | } |
78 | } | 87 | } |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 4ff897ca5..bc4b47b70 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -12,8 +12,7 @@ use test_utils::covers; | |||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | mock::{CrateGraphFixture, MockDatabase}, | 14 | mock::{CrateGraphFixture, MockDatabase}, |
15 | nameres::Resolution, | 15 | Crate, |
16 | Crate, Either, | ||
17 | }; | 16 | }; |
18 | 17 | ||
19 | use super::*; | 18 | use super::*; |
@@ -37,35 +36,38 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { | |||
37 | *buf += path; | 36 | *buf += path; |
38 | *buf += "\n"; | 37 | *buf += "\n"; |
39 | 38 | ||
40 | let items = map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::A(it))); | 39 | let mut entries = map.modules[module] |
41 | let macros = map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::B(m))); | 40 | .scope |
42 | let mut entries = items.chain(macros).collect::<Vec<_>>(); | 41 | .items |
43 | 42 | .iter() | |
43 | .map(|(name, res)| (name, res.def)) | ||
44 | .collect::<Vec<_>>(); | ||
44 | entries.sort_by_key(|(name, _)| *name); | 45 | entries.sort_by_key(|(name, _)| *name); |
46 | |||
45 | for (name, res) in entries { | 47 | for (name, res) in entries { |
46 | match res { | 48 | *buf += &format!("{}:", name); |
47 | Either::A(it) => { | 49 | |
48 | *buf += &format!("{}: {}\n", name, dump_resolution(it)); | 50 | if res.types.is_some() { |
49 | } | 51 | *buf += " t"; |
50 | Either::B(_) => { | 52 | } |
51 | *buf += &format!("{}: m\n", name); | 53 | if res.values.is_some() { |
52 | } | 54 | *buf += " v"; |
55 | } | ||
56 | if res.macros.is_some() { | ||
57 | *buf += " m"; | ||
58 | } | ||
59 | if res.is_none() { | ||
60 | *buf += " _"; | ||
53 | } | 61 | } |
62 | |||
63 | *buf += "\n"; | ||
54 | } | 64 | } |
65 | |||
55 | for (name, child) in map.modules[module].children.iter() { | 66 | for (name, child) in map.modules[module].children.iter() { |
56 | let path = path.to_string() + &format!("::{}", name); | 67 | let path = path.to_string() + &format!("::{}", name); |
57 | go(buf, map, &path, *child); | 68 | go(buf, map, &path, *child); |
58 | } | 69 | } |
59 | } | 70 | } |
60 | |||
61 | fn dump_resolution(resolution: &Resolution) -> &'static str { | ||
62 | match (resolution.def.types.is_some(), resolution.def.values.is_some()) { | ||
63 | (true, true) => "t v", | ||
64 | (true, false) => "t", | ||
65 | (false, true) => "v", | ||
66 | (false, false) => "_", | ||
67 | } | ||
68 | } | ||
69 | } | 71 | } |
70 | 72 | ||
71 | fn def_map(fixtute: &str) -> String { | 73 | fn def_map(fixtute: &str) -> String { |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index ebc4d6890..20ee63c67 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -21,7 +21,6 @@ fn macro_rules_are_globally_visible() { | |||
21 | ⋮crate | 21 | ⋮crate |
22 | ⋮Foo: t v | 22 | ⋮Foo: t v |
23 | ⋮nested: t | 23 | ⋮nested: t |
24 | ⋮structs: m | ||
25 | ⋮ | 24 | ⋮ |
26 | ⋮crate::nested | 25 | ⋮crate::nested |
27 | ⋮Bar: t v | 26 | ⋮Bar: t v |
@@ -47,7 +46,6 @@ fn macro_rules_can_define_modules() { | |||
47 | ); | 46 | ); |
48 | assert_snapshot!(map, @r###" | 47 | assert_snapshot!(map, @r###" |
49 | ⋮crate | 48 | ⋮crate |
50 | ⋮m: m | ||
51 | ⋮n1: t | 49 | ⋮n1: t |
52 | ⋮ | 50 | ⋮ |
53 | ⋮crate::n1 | 51 | ⋮crate::n1 |
@@ -133,7 +131,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
133 | ⋮crate | 131 | ⋮crate |
134 | ⋮Foo: t v | 132 | ⋮Foo: t v |
135 | ⋮bar: m | 133 | ⋮bar: m |
136 | ⋮baz: m | ||
137 | ⋮foo: m | 134 | ⋮foo: m |
138 | "###); | 135 | "###); |
139 | } | 136 | } |
@@ -271,7 +268,6 @@ fn prelude_cycle() { | |||
271 | ⋮prelude: t | 268 | ⋮prelude: t |
272 | ⋮ | 269 | ⋮ |
273 | ⋮crate::prelude | 270 | ⋮crate::prelude |
274 | ⋮declare_mod: m | ||
275 | "###); | 271 | "###); |
276 | } | 272 | } |
277 | 273 | ||
@@ -345,7 +341,6 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
345 | ⋮Ok: t v | 341 | ⋮Ok: t v |
346 | ⋮OkAfter: t v | 342 | ⋮OkAfter: t v |
347 | ⋮OkShadowStop: t v | 343 | ⋮OkShadowStop: t v |
348 | ⋮foo: m | ||
349 | ⋮m1: t | 344 | ⋮m1: t |
350 | ⋮m2: t | 345 | ⋮m2: t |
351 | ⋮m3: t | 346 | ⋮m3: t |
@@ -354,28 +349,132 @@ fn plain_macros_are_legacy_textual_scoped() { | |||
354 | ⋮ok_double_macro_use_shadow: v | 349 | ⋮ok_double_macro_use_shadow: v |
355 | ⋮ | 350 | ⋮ |
356 | ⋮crate::m7 | 351 | ⋮crate::m7 |
357 | ⋮baz: m | ||
358 | ⋮ | 352 | ⋮ |
359 | ⋮crate::m1 | 353 | ⋮crate::m1 |
360 | ⋮bar: m | ||
361 | ⋮ | 354 | ⋮ |
362 | ⋮crate::m5 | 355 | ⋮crate::m5 |
363 | ⋮m6: t | 356 | ⋮m6: t |
364 | ⋮ | 357 | ⋮ |
365 | ⋮crate::m5::m6 | 358 | ⋮crate::m5::m6 |
366 | ⋮foo: m | ||
367 | ⋮ | 359 | ⋮ |
368 | ⋮crate::m2 | 360 | ⋮crate::m2 |
369 | ⋮ | 361 | ⋮ |
370 | ⋮crate::m3 | 362 | ⋮crate::m3 |
371 | ⋮OkAfterInside: t v | 363 | ⋮OkAfterInside: t v |
372 | ⋮OkMacroUse: t v | 364 | ⋮OkMacroUse: t v |
373 | ⋮foo: m | ||
374 | ⋮m4: t | 365 | ⋮m4: t |
375 | ⋮ok_shadow: v | 366 | ⋮ok_shadow: v |
376 | ⋮ | 367 | ⋮ |
377 | ⋮crate::m3::m4 | 368 | ⋮crate::m3::m4 |
378 | ⋮bar: m | ||
379 | ⋮ok_shadow_deep: v | 369 | ⋮ok_shadow_deep: v |
380 | "###); | 370 | "###); |
381 | } | 371 | } |
372 | |||
373 | #[test] | ||
374 | fn type_value_macro_live_in_different_scopes() { | ||
375 | let map = def_map( | ||
376 | " | ||
377 | //- /main.rs | ||
378 | #[macro_export] | ||
379 | macro_rules! foo { | ||
380 | ($x:ident) => { type $x = (); } | ||
381 | } | ||
382 | |||
383 | foo!(foo); | ||
384 | use foo as bar; | ||
385 | |||
386 | use self::foo as baz; | ||
387 | fn baz() {} | ||
388 | ", | ||
389 | ); | ||
390 | assert_snapshot!(map, @r###" | ||
391 | ⋮crate | ||
392 | ⋮bar: t m | ||
393 | ⋮baz: t v m | ||
394 | ⋮foo: t m | ||
395 | "###); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn macro_use_can_be_aliased() { | ||
400 | let map = def_map_with_crate_graph( | ||
401 | " | ||
402 | //- /main.rs | ||
403 | #[macro_use] | ||
404 | extern crate foo; | ||
405 | |||
406 | foo!(Direct); | ||
407 | bar!(Alias); | ||
408 | |||
409 | //- /lib.rs | ||
410 | use crate::foo as bar; | ||
411 | |||
412 | mod m { | ||
413 | #[macro_export] | ||
414 | macro_rules! foo { | ||
415 | ($x:ident) => { struct $x; } | ||
416 | } | ||
417 | } | ||
418 | ", | ||
419 | crate_graph! { | ||
420 | "main": ("/main.rs", ["foo"]), | ||
421 | "foo": ("/lib.rs", []), | ||
422 | }, | ||
423 | ); | ||
424 | assert_snapshot!(map, @r###" | ||
425 | ⋮crate | ||
426 | ⋮Alias: t v | ||
427 | ⋮Direct: t v | ||
428 | ⋮foo: t | ||
429 | "###); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn path_quantified_macros() { | ||
434 | let map = def_map( | ||
435 | " | ||
436 | //- /main.rs | ||
437 | macro_rules! foo { | ||
438 | ($x:ident) => { struct $x; } | ||
439 | } | ||
440 | |||
441 | crate::foo!(NotResolved); | ||
442 | |||
443 | crate::bar!(OkCrate); | ||
444 | bar!(OkPlain); | ||
445 | alias1!(NotHere); | ||
446 | m::alias1!(OkAliasPlain); | ||
447 | m::alias2!(OkAliasSuper); | ||
448 | m::alias3!(OkAliasCrate); | ||
449 | not_found!(NotFound); | ||
450 | |||
451 | mod m { | ||
452 | #[macro_export] | ||
453 | macro_rules! bar { | ||
454 | ($x:ident) => { struct $x; } | ||
455 | } | ||
456 | |||
457 | pub use bar as alias1; | ||
458 | pub use super::bar as alias2; | ||
459 | pub use crate::bar as alias3; | ||
460 | pub use self::bar as not_found; | ||
461 | } | ||
462 | ", | ||
463 | ); | ||
464 | assert_snapshot!(map, @r###" | ||
465 | ⋮crate | ||
466 | ⋮OkAliasCrate: t v | ||
467 | ⋮OkAliasPlain: t v | ||
468 | ⋮OkAliasSuper: t v | ||
469 | ⋮OkCrate: t v | ||
470 | ⋮OkPlain: t v | ||
471 | ⋮bar: m | ||
472 | ⋮m: t | ||
473 | ⋮ | ||
474 | ⋮crate::m | ||
475 | ⋮alias1: m | ||
476 | ⋮alias2: m | ||
477 | ⋮alias3: m | ||
478 | ⋮not_found: _ | ||
479 | "###); | ||
480 | } | ||