diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-06 19:44:26 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-08 18:34:53 +0100 |
commit | 26b092bd3b431559d7aafbf42882f978c0bb3dab (patch) | |
tree | 194c41ab1320730d7f08823127404056e235cf2e /crates/ra_hir/src | |
parent | e0f305a6bf710f64f789f909da93a8c362823b67 (diff) |
Resolve textual scoped macros inside item
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 35 |
4 files changed, 65 insertions, 9 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index e6bf0e90c..befbb2a9b 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -489,16 +489,21 @@ impl CrateDefMap { | |||
489 | name: &Name, | 489 | name: &Name, |
490 | ) -> ItemOrMacro { | 490 | ) -> ItemOrMacro { |
491 | // Resolve in: | 491 | // Resolve in: |
492 | // - textual scoped macros | ||
492 | // - current module / scope | 493 | // - current module / scope |
493 | // - extern prelude | 494 | // - extern prelude |
494 | // - std prelude | 495 | // - std prelude |
496 | let from_textual_mcro = self[module] | ||
497 | .scope | ||
498 | .get_textual_macro(name) | ||
499 | .map_or_else(|| Either::A(PerNs::none()), Either::B); | ||
495 | let from_scope = | 500 | let from_scope = |
496 | self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); | 501 | self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); |
497 | let from_extern_prelude = | 502 | let from_extern_prelude = |
498 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | 503 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); |
499 | let from_prelude = self.resolve_in_prelude(db, name); | 504 | let from_prelude = self.resolve_in_prelude(db, name); |
500 | 505 | ||
501 | or(from_scope, or(Either::A(from_extern_prelude), from_prelude)) | 506 | or(from_textual_mcro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude))) |
502 | } | 507 | } |
503 | 508 | ||
504 | fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> { | 509 | 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 f897547e3..10c32ffa1 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 | ||
21 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 21 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { |
@@ -156,9 +156,6 @@ where | |||
156 | /// the definition of current module. | 156 | /// the definition of current module. |
157 | /// And also, `macro_use` on a module will import all textual macros visable inside to | 157 | /// And also, `macro_use` on a module will import all textual macros visable inside to |
158 | /// current textual scope, with possible shadowing. | 158 | /// current textual scope, with possible shadowing. |
159 | /// | ||
160 | /// In a single module, the order of definition/usage of textual scoped macros matters. | ||
161 | /// But we ignore it here to make it easy to implement. | ||
162 | fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { | 159 | fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { |
163 | // Always shadowing | 160 | // Always shadowing |
164 | self.def_map.modules[module_id] | 161 | self.def_map.modules[module_id] |
@@ -700,8 +697,13 @@ where | |||
700 | return; | 697 | return; |
701 | } | 698 | } |
702 | 699 | ||
703 | // Case 3: path to a macro from another crate, expand during name resolution | 700 | // Case 3: resolve in module scope, expand during name resolution. |
704 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) | 701 | // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. |
702 | let mut path = mac.path.clone(); | ||
703 | if path.is_ident() { | ||
704 | path.kind = PathKind::Self_; | ||
705 | } | ||
706 | self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); | ||
705 | } | 707 | } |
706 | 708 | ||
707 | fn import_all_textual_macros(&mut self, module_id: CrateModuleId) { | 709 | fn import_all_textual_macros(&mut self, module_id: CrateModuleId) { |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 8f0db95f2..a894c6836 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -279,7 +279,7 @@ fn prelude_cycle() { | |||
279 | } | 279 | } |
280 | 280 | ||
281 | #[test] | 281 | #[test] |
282 | fn plain_macros_are_textual_scoped_between_modules() { | 282 | fn plain_macros_are_textual_scoped() { |
283 | let map = def_map( | 283 | let map = def_map( |
284 | r#" | 284 | r#" |
285 | //- /main.rs | 285 | //- /main.rs |
@@ -310,6 +310,15 @@ fn plain_macros_are_textual_scoped_between_modules() { | |||
310 | } | 310 | } |
311 | foo!(ok_double_macro_use_shadow); | 311 | foo!(ok_double_macro_use_shadow); |
312 | 312 | ||
313 | baz!(NotFoundBefore); | ||
314 | #[macro_use] | ||
315 | mod m7 { | ||
316 | macro_rules! baz { | ||
317 | ($x:ident) => { struct $x; } | ||
318 | } | ||
319 | } | ||
320 | baz!(OkAfter); | ||
321 | |||
313 | //- /m1.rs | 322 | //- /m1.rs |
314 | foo!(NotFoundBeforeInside1); | 323 | foo!(NotFoundBeforeInside1); |
315 | macro_rules! bar { | 324 | macro_rules! bar { |
@@ -337,14 +346,19 @@ fn plain_macros_are_textual_scoped_between_modules() { | |||
337 | assert_snapshot!(map, @r###" | 346 | assert_snapshot!(map, @r###" |
338 | ⋮crate | 347 | ⋮crate |
339 | ⋮Ok: t v | 348 | ⋮Ok: t v |
349 | ⋮OkAfter: t v | ||
340 | ⋮OkShadowStop: t v | 350 | ⋮OkShadowStop: t v |
341 | ⋮foo: m | 351 | ⋮foo: m |
342 | ⋮m1: t | 352 | ⋮m1: t |
343 | ⋮m2: t | 353 | ⋮m2: t |
344 | ⋮m3: t | 354 | ⋮m3: t |
345 | ⋮m5: t | 355 | ⋮m5: t |
356 | ⋮m7: t | ||
346 | ⋮ok_double_macro_use_shadow: v | 357 | ⋮ok_double_macro_use_shadow: v |
347 | ⋮ | 358 | ⋮ |
359 | ⋮crate::m7 | ||
360 | ⋮baz: m | ||
361 | ⋮ | ||
348 | ⋮crate::m1 | 362 | ⋮crate::m1 |
349 | ⋮bar: m | 363 | ⋮bar: m |
350 | ⋮ | 364 | ⋮ |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index c4bddde85..f2d5b115e 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] | ||
2807 | fn infer_textual_scoped_macros_expanded() { | ||
2808 | assert_snapshot!( | ||
2809 | infer(r#" | ||
2810 | struct Foo(Vec<i32>); | ||
2811 | |||
2812 | #[macro_use] | ||
2813 | mod m { | ||
2814 | macro_rules! foo { | ||
2815 | ($($item:expr),*) => { | ||
2816 | { | ||
2817 | Foo(vec![$($item,)*]) | ||
2818 | } | ||
2819 | }; | ||
2820 | } | ||
2821 | } | ||
2822 | |||
2823 | fn 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] |
2808 | fn method_resolution_trait_before_autoref() { | 2843 | fn method_resolution_trait_before_autoref() { |