aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/nameres.rs25
-rw-r--r--crates/ra_hir/src/nameres/collector.rs91
-rw-r--r--crates/ra_hir/src/nameres/raw.rs12
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs108
-rw-r--r--crates/ra_hir/src/ty/tests.rs35
5 files changed, 229 insertions, 42 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 7de422128..74546e5e2 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -138,7 +138,21 @@ pub(crate) struct ModuleData {
138#[derive(Debug, Default, PartialEq, Eq, Clone)] 138#[derive(Debug, Default, PartialEq, Eq, Clone)]
139pub struct ModuleScope { 139pub struct ModuleScope {
140 items: FxHashMap<Name, Resolution>, 140 items: FxHashMap<Name, Resolution>,
141 /// Macros in current module scoped
142 ///
143 /// This scope works exactly the same way that item scoping does.
144 /// Macro invocation with quantified path will search in it.
145 /// See details below.
141 macros: FxHashMap<Name, MacroDef>, 146 macros: FxHashMap<Name, MacroDef>,
147 /// Macros visable in current module in legacy textual scope
148 ///
149 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
150 /// If it yields no result, then it turns to module scoped `macros`.
151 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
152 /// and only normal scoped `macros` will be searched in.
153 ///
154 /// Note that this automatically inherit macros defined textually before the definition of module itself.
155 legacy_macros: FxHashMap<Name, MacroDef>,
142} 156}
143 157
144static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| { 158static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
@@ -164,6 +178,7 @@ impl ModuleScope {
164 _ => None, 178 _ => None,
165 }) 179 })
166 } 180 }
181 /// It resolves in module scope. Textual scoped macros are ignored here.
167 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> { 182 fn get_item_or_macro(&self, name: &Name) -> Option<ItemOrMacro> {
168 match (self.get(name), self.macros.get(name)) { 183 match (self.get(name), self.macros.get(name)) {
169 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)), 184 (Some(item), _) if !item.def.is_none() => Some(Either::A(item.def)),
@@ -171,6 +186,9 @@ impl ModuleScope {
171 _ => None, 186 _ => None,
172 } 187 }
173 } 188 }
189 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
190 self.legacy_macros.get(name).copied()
191 }
174} 192}
175 193
176type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>; 194type ItemOrMacro = Either<PerNs<ModuleDef>, MacroDef>;
@@ -484,16 +502,21 @@ impl CrateDefMap {
484 name: &Name, 502 name: &Name,
485 ) -> ItemOrMacro { 503 ) -> ItemOrMacro {
486 // Resolve in: 504 // Resolve in:
505 // - legacy scope
487 // - current module / scope 506 // - current module / scope
488 // - extern prelude 507 // - extern prelude
489 // - std prelude 508 // - std prelude
509 let from_legacy_macro = self[module]
510 .scope
511 .get_legacy_macro(name)
512 .map_or_else(|| Either::A(PerNs::none()), Either::B);
490 let from_scope = 513 let from_scope =
491 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); 514 self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none()));
492 let from_extern_prelude = 515 let from_extern_prelude =
493 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 516 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
494 let from_prelude = self.resolve_in_prelude(db, name); 517 let from_prelude = self.resolve_in_prelude(db, name);
495 518
496 or(from_scope, or(Either::A(from_extern_prelude), from_prelude)) 519 or(from_legacy_macro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude)))
497 } 520 }
498 521
499 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { 522 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 1c0d4369e..09cda7656 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -14,8 +14,8 @@ use crate::{
14 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, 14 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
15 ReachedFixedPoint, Resolution, ResolveMode, 15 ReachedFixedPoint, Resolution, ResolveMode,
16 }, 16 },
17 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, Struct, Trait, 17 AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
18 TypeAlias, Union, 18 Struct, Trait, TypeAlias, Union,
19}; 19};
20 20
21pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 21pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -40,7 +40,6 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
40 glob_imports: FxHashMap::default(), 40 glob_imports: FxHashMap::default(),
41 unresolved_imports: Vec::new(), 41 unresolved_imports: Vec::new(),
42 unexpanded_macros: Vec::new(), 42 unexpanded_macros: Vec::new(),
43 global_macro_scope: FxHashMap::default(),
44 macro_stack_monitor: MacroStackMonitor::default(), 43 macro_stack_monitor: MacroStackMonitor::default(),
45 }; 44 };
46 collector.collect(); 45 collector.collect();
@@ -82,7 +81,6 @@ struct DefCollector<DB> {
82 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 81 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
83 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 82 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
84 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, 83 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
85 global_macro_scope: FxHashMap<Name, MacroDefId>,
86 84
87 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 85 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
88 /// To prevent stack overflow, we add a deep counter here for prevent that. 86 /// To prevent stack overflow, we add a deep counter here for prevent that.
@@ -136,20 +134,6 @@ where
136 macro_id: MacroDefId, 134 macro_id: MacroDefId,
137 export: bool, 135 export: bool,
138 ) { 136 ) {
139 // macro-by-example in Rust have completely weird name resolution logic,
140 // unlike anything else in the language. We'd don't fully implement yet,
141 // just give a somewhat precise approximation.
142 //
143 // Specifically, we store a set of visible macros in each module, just
144 // like how we do with usual items. This is wrong, however, because
145 // macros can be shadowed and their scopes are mostly unrelated to
146 // modules. To paper over the second problem, we also maintain
147 // `global_macro_scope` which works when we construct `CrateDefMap`, but
148 // is completely ignored in expressions.
149 //
150 // What we should do is that, in CrateDefMap, we should maintain a
151 // separate tower of macro scopes, with ids. Then, for each item in the
152 // module, we need to store it's macro scope.
153 let def = Either::B(MacroDef { id: macro_id }); 137 let def = Either::B(MacroDef { id: macro_id });
154 138
155 // In Rust, `#[macro_export]` macros are unconditionally visible at the 139 // In Rust, `#[macro_export]` macros are unconditionally visible at the
@@ -162,13 +146,29 @@ where
162 self.def_map.exported_macros.insert(name.clone(), macro_id); 146 self.def_map.exported_macros.insert(name.clone(), macro_id);
163 } 147 }
164 self.update(module_id, None, &[(name.clone(), def)]); 148 self.update(module_id, None, &[(name.clone(), def)]);
165 self.global_macro_scope.insert(name, macro_id); 149 self.define_legacy_macro(module_id, name.clone(), macro_id);
150 }
151
152 /// Define a legacy textual scoped macro in module
153 ///
154 /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module.
155 /// It will clone all macros from parent legacy scope, whose definition is prior to
156 /// the definition of current module.
157 /// And also, `macro_use` on a module will import all legacy macros visable inside to
158 /// current legacy scope, with possible shadowing.
159 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) {
160 // Always shadowing
161 self.def_map.modules[module_id].scope.legacy_macros.insert(name, MacroDef { id: macro_id });
166 } 162 }
167 163
168 /// Import macros from `#[macro_use] extern crate`. 164 /// Import macros from `#[macro_use] extern crate`.
169 /// 165 ///
170 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. 166 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
171 fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { 167 fn import_macros_from_extern_crate(
168 &mut self,
169 current_module_id: CrateModuleId,
170 import: &raw::ImportData,
171 ) {
172 log::debug!( 172 log::debug!(
173 "importing macros from extern crate: {:?} ({:?})", 173 "importing macros from extern crate: {:?} ({:?})",
174 import, 174 import,
@@ -184,14 +184,14 @@ where
184 184
185 if let Some(ModuleDef::Module(m)) = res.take_types() { 185 if let Some(ModuleDef::Module(m)) = res.take_types() {
186 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 186 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
187 self.import_all_macros_exported(m); 187 self.import_all_macros_exported(current_module_id, m);
188 } 188 }
189 } 189 }
190 190
191 fn import_all_macros_exported(&mut self, module: Module) { 191 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, module: Module) {
192 let item_map = self.db.crate_def_map(module.krate); 192 let item_map = self.db.crate_def_map(module.krate);
193 for (name, &macro_id) in &item_map.exported_macros { 193 for (name, &macro_id) in &item_map.exported_macros {
194 self.global_macro_scope.insert(name.clone(), macro_id); 194 self.define_legacy_macro(current_module_id, name.clone(), macro_id);
195 } 195 }
196 } 196 }
197 197
@@ -528,7 +528,7 @@ where
528 if let Some(prelude_module) = self.def_collector.def_map.prelude { 528 if let Some(prelude_module) = self.def_collector.def_map.prelude {
529 if prelude_module.krate != self.def_collector.def_map.krate { 529 if prelude_module.krate != self.def_collector.def_map.krate {
530 tested_by!(prelude_is_macro_use); 530 tested_by!(prelude_is_macro_use);
531 self.def_collector.import_all_macros_exported(prelude_module); 531 self.def_collector.import_all_macros_exported(self.module_id, prelude_module);
532 } 532 }
533 } 533 }
534 534
@@ -539,7 +539,7 @@ where
539 if let raw::RawItem::Import(import_id) = *item { 539 if let raw::RawItem::Import(import_id) = *item {
540 let import = self.raw_items[import_id].clone(); 540 let import = self.raw_items[import_id].clone();
541 if import.is_extern_crate && import.is_macro_use { 541 if import.is_extern_crate && import.is_macro_use {
542 self.def_collector.import_macros_from_extern_crate(&import); 542 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
543 } 543 }
544 } 544 }
545 } 545 }
@@ -561,10 +561,11 @@ where
561 fn collect_module(&mut self, module: &raw::ModuleData) { 561 fn collect_module(&mut self, module: &raw::ModuleData) {
562 match module { 562 match module {
563 // inline module, just recurse 563 // inline module, just recurse
564 raw::ModuleData::Definition { name, items, ast_id, attr_path } => { 564 raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => {
565 let module_id = 565 let module_id =
566 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 566 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
567 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; 567 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() };
568
568 ModCollector { 569 ModCollector {
569 def_collector: &mut *self.def_collector, 570 def_collector: &mut *self.def_collector,
570 module_id, 571 module_id,
@@ -573,9 +574,12 @@ where
573 parent_module: Some(parent_module), 574 parent_module: Some(parent_module),
574 } 575 }
575 .collect(&*items); 576 .collect(&*items);
577 if *is_macro_use {
578 self.import_all_legacy_macros(module_id);
579 }
576 } 580 }
577 // out of line module, resolve, parse and recurse 581 // out of line module, resolve, parse and recurse
578 raw::ModuleData::Declaration { name, ast_id, attr_path } => { 582 raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => {
579 let ast_id = ast_id.with_file_id(self.file_id); 583 let ast_id = ast_id.with_file_id(self.file_id);
580 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 584 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
581 match resolve_submodule( 585 match resolve_submodule(
@@ -596,7 +600,10 @@ where
596 raw_items: &raw_items, 600 raw_items: &raw_items,
597 parent_module: None, 601 parent_module: None,
598 } 602 }
599 .collect(raw_items.items()) 603 .collect(raw_items.items());
604 if *is_macro_use {
605 self.import_all_legacy_macros(module_id);
606 }
600 } 607 }
601 Err(candidate) => self.def_collector.def_map.diagnostics.push( 608 Err(candidate) => self.def_collector.def_map.diagnostics.push(
602 DefDiagnostic::UnresolvedModule { 609 DefDiagnostic::UnresolvedModule {
@@ -621,6 +628,7 @@ where
621 modules[res].parent = Some(self.module_id); 628 modules[res].parent = Some(self.module_id);
622 modules[res].declaration = Some(declaration); 629 modules[res].declaration = Some(declaration);
623 modules[res].definition = definition; 630 modules[res].definition = definition;
631 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
624 modules[self.module_id].children.insert(name.clone(), res); 632 modules[self.module_id].children.insert(name.clone(), res);
625 let resolution = Resolution { 633 let resolution = Resolution {
626 def: PerNs::types( 634 def: PerNs::types(
@@ -674,20 +682,32 @@ where
674 682
675 let ast_id = mac.ast_id.with_file_id(self.file_id); 683 let ast_id = mac.ast_id.with_file_id(self.file_id);
676 684
677 // Case 2: try to expand macro_rules from this crate, triggering 685 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering
678 // recursive item collection. 686 // recursive item collection.
679 if let Some(macro_id) = 687 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
680 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(&name)) 688 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
681 { 689 }) {
682 let def = *macro_id; 690 let def = macro_def.id;
683 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); 691 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db);
684 692
685 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); 693 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
686 return; 694 return;
687 } 695 }
688 696
689 // Case 3: path to a macro from another crate, expand during name resolution 697 // Case 3: resolve in module scope, expand during name resolution.
690 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) 698 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
699 let mut path = mac.path.clone();
700 if path.is_ident() {
701 path.kind = PathKind::Self_;
702 }
703 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path));
704 }
705
706 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) {
707 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
708 for (name, macro_) in macros {
709 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_.id);
710 }
691 } 711 }
692} 712}
693 713
@@ -715,7 +735,6 @@ mod tests {
715 glob_imports: FxHashMap::default(), 735 glob_imports: FxHashMap::default(),
716 unresolved_imports: Vec::new(), 736 unresolved_imports: Vec::new(),
717 unexpanded_macros: Vec::new(), 737 unexpanded_macros: Vec::new(),
718 global_macro_scope: FxHashMap::default(),
719 macro_stack_monitor: monitor, 738 macro_stack_monitor: monitor,
720 }; 739 };
721 collector.collect(); 740 collector.collect();
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 7963736e0..c646d3d00 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -134,12 +134,14 @@ pub(super) enum ModuleData {
134 name: Name, 134 name: Name,
135 ast_id: FileAstId<ast::Module>, 135 ast_id: FileAstId<ast::Module>,
136 attr_path: Option<SmolStr>, 136 attr_path: Option<SmolStr>,
137 is_macro_use: bool,
137 }, 138 },
138 Definition { 139 Definition {
139 name: Name, 140 name: Name,
140 ast_id: FileAstId<ast::Module>, 141 ast_id: FileAstId<ast::Module>,
141 items: Vec<RawItem>, 142 items: Vec<RawItem>,
142 attr_path: Option<SmolStr>, 143 attr_path: Option<SmolStr>,
144 is_macro_use: bool,
143 }, 145 },
144} 146}
145 147
@@ -267,10 +269,15 @@ impl RawItemsCollector {
267 }; 269 };
268 270
269 let ast_id = self.source_ast_id_map.ast_id(&module); 271 let ast_id = self.source_ast_id_map.ast_id(&module);
272 let is_macro_use = module.has_atom_attr("macro_use");
270 if module.has_semi() { 273 if module.has_semi() {
271 let attr_path = extract_mod_path_attribute(&module); 274 let attr_path = extract_mod_path_attribute(&module);
272 let item = 275 let item = self.raw_items.modules.alloc(ModuleData::Declaration {
273 self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); 276 name,
277 ast_id,
278 attr_path,
279 is_macro_use,
280 });
274 self.push_item(current_module, RawItem::Module(item)); 281 self.push_item(current_module, RawItem::Module(item));
275 return; 282 return;
276 } 283 }
@@ -282,6 +289,7 @@ impl RawItemsCollector {
282 ast_id, 289 ast_id,
283 items: Vec::new(), 290 items: Vec::new(),
284 attr_path, 291 attr_path,
292 is_macro_use,
285 }); 293 });
286 self.process_module(Some(item), item_list); 294 self.process_module(Some(item), item_list);
287 self.push_item(current_module, RawItem::Module(item)); 295 self.push_item(current_module, RawItem::Module(item));
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index c62152d26..ebc4d6890 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -268,12 +268,114 @@ fn prelude_cycle() {
268 ); 268 );
269 assert_snapshot!(map, @r###" 269 assert_snapshot!(map, @r###"
270 ⋮crate 270 ⋮crate
271 ⋮foo: t
272 ⋮prelude: t 271 ⋮prelude: t
273 272
274 ⋮crate::prelude 273 ⋮crate::prelude
275 ⋮declare_mod: m 274 ⋮declare_mod: m
276 275 "###);
277 ⋮crate::foo 276}
277
278#[test]
279fn plain_macros_are_legacy_textual_scoped() {
280 let map = def_map(
281 r#"
282 //- /main.rs
283 mod m1;
284 bar!(NotFoundNotMacroUse);
285
286 mod m2 {
287 foo!(NotFoundBeforeInside2);
288 }
289
290 macro_rules! foo {
291 ($x:ident) => { struct $x; }
292 }
293 foo!(Ok);
294
295 mod m3;
296 foo!(OkShadowStop);
297 bar!(NotFoundMacroUseStop);
298
299 #[macro_use]
300 mod m5 {
301 #[macro_use]
302 mod m6 {
303 macro_rules! foo {
304 ($x:ident) => { fn $x() {} }
305 }
306 }
307 }
308 foo!(ok_double_macro_use_shadow);
309
310 baz!(NotFoundBefore);
311 #[macro_use]
312 mod m7 {
313 macro_rules! baz {
314 ($x:ident) => { struct $x; }
315 }
316 }
317 baz!(OkAfter);
318
319 //- /m1.rs
320 foo!(NotFoundBeforeInside1);
321 macro_rules! bar {
322 ($x:ident) => { struct $x; }
323 }
324
325 //- /m3/mod.rs
326 foo!(OkAfterInside);
327 macro_rules! foo {
328 ($x:ident) => { fn $x() {} }
329 }
330 foo!(ok_shadow);
331
332 #[macro_use]
333 mod m4;
334 bar!(OkMacroUse);
335
336 //- /m3/m4.rs
337 foo!(ok_shadow_deep);
338 macro_rules! bar {
339 ($x:ident) => { struct $x; }
340 }
341 "#,
342 );
343 assert_snapshot!(map, @r###"
344 ⋮crate
345 ⋮Ok: t v
346 ⋮OkAfter: t v
347 ⋮OkShadowStop: t v
348 ⋮foo: m
349 ⋮m1: t
350 ⋮m2: t
351 ⋮m3: t
352 ⋮m5: t
353 ⋮m7: t
354 ⋮ok_double_macro_use_shadow: v
355
356 ⋮crate::m7
357 ⋮baz: m
358
359 ⋮crate::m1
360 ⋮bar: m
361
362 ⋮crate::m5
363 ⋮m6: t
364
365 ⋮crate::m5::m6
366 ⋮foo: m
367
368 ⋮crate::m2
369
370 ⋮crate::m3
371 ⋮OkAfterInside: t v
372 ⋮OkMacroUse: t v
373 ⋮foo: m
374 ⋮m4: t
375 ⋮ok_shadow: v
376
377 ⋮crate::m3::m4
378 ⋮bar: m
379 ⋮ok_shadow_deep: v
278 "###); 380 "###);
279} 381}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c4bddde85..25716fe8c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2803,6 +2803,41 @@ fn main() {
2803 ); 2803 );
2804} 2804}
2805 2805
2806#[test]
2807fn infer_legacy_textual_scoped_macros_expanded() {
2808 assert_snapshot!(
2809 infer(r#"
2810struct Foo(Vec<i32>);
2811
2812#[macro_use]
2813mod m {
2814 macro_rules! foo {
2815 ($($item:expr),*) => {
2816 {
2817 Foo(vec![$($item,)*])
2818 }
2819 };
2820 }
2821}
2822
2823fn main() {
2824 let x = foo!(1,2);
2825 let y = crate::foo!(1,2);
2826}
2827"#),
2828 @r###"
2829 ![0; 17) '{Foo(v...,2,])}': Foo
2830 ![1; 4) 'Foo': Foo({unknown}) -> Foo
2831 ![1; 16) 'Foo(vec![1,2,])': Foo
2832 ![5; 15) 'vec![1,2,]': {unknown}
2833 [195; 251) '{ ...,2); }': ()
2834 [205; 206) 'x': Foo
2835 [228; 229) 'y': {unknown}
2836 [232; 248) 'crate:...!(1,2)': {unknown}
2837 "###
2838 );
2839}
2840
2806#[ignore] 2841#[ignore]
2807#[test] 2842#[test]
2808fn method_resolution_trait_before_autoref() { 2843fn method_resolution_trait_before_autoref() {