From 26b092bd3b431559d7aafbf42882f978c0bb3dab Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Sat, 7 Sep 2019 02:44:26 +0800 Subject: Resolve textual scoped macros inside item --- crates/ra_hir/src/nameres.rs | 7 ++++++- crates/ra_hir/src/nameres/collector.rs | 16 +++++++------- crates/ra_hir/src/nameres/tests/macros.rs | 16 +++++++++++++- 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 { name: &Name, ) -> ItemOrMacro { // Resolve in: + // - textual scoped macros // - current module / scope // - extern prelude // - std prelude + let from_textual_mcro = self[module] + .scope + .get_textual_macro(name) + .map_or_else(|| Either::A(PerNs::none()), Either::B); let from_scope = self[module].scope.get_item_or_macro(name).unwrap_or_else(|| Either::A(PerNs::none())); let from_extern_prelude = self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); let from_prelude = self.resolve_in_prelude(db, name); - or(from_scope, or(Either::A(from_extern_prelude), from_prelude)) + or(from_textual_mcro, or(from_scope, or(Either::A(from_extern_prelude), from_prelude))) } fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 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::{ raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, }, - AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, Struct, Trait, - TypeAlias, Union, + AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, + Struct, Trait, TypeAlias, Union, }; pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { @@ -156,9 +156,6 @@ where /// the definition of current module. /// And also, `macro_use` on a module will import all textual macros visable inside to /// current textual scope, with possible shadowing. - /// - /// In a single module, the order of definition/usage of textual scoped macros matters. - /// But we ignore it here to make it easy to implement. fn define_textual_macro(&mut self, module_id: CrateModuleId, name: Name, macro_id: MacroDefId) { // Always shadowing self.def_map.modules[module_id] @@ -700,8 +697,13 @@ where return; } - // Case 3: path to a macro from another crate, expand during name resolution - self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone())) + // Case 3: resolve in module scope, expand during name resolution. + // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. + let mut path = mac.path.clone(); + if path.is_ident() { + path.kind = PathKind::Self_; + } + self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); } 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() { } #[test] -fn plain_macros_are_textual_scoped_between_modules() { +fn plain_macros_are_textual_scoped() { let map = def_map( r#" //- /main.rs @@ -310,6 +310,15 @@ fn plain_macros_are_textual_scoped_between_modules() { } foo!(ok_double_macro_use_shadow); + baz!(NotFoundBefore); + #[macro_use] + mod m7 { + macro_rules! baz { + ($x:ident) => { struct $x; } + } + } + baz!(OkAfter); + //- /m1.rs foo!(NotFoundBeforeInside1); macro_rules! bar { @@ -337,14 +346,19 @@ fn plain_macros_are_textual_scoped_between_modules() { assert_snapshot!(map, @r###" ⋮crate ⋮Ok: t v + ⋮OkAfter: t v ⋮OkShadowStop: t v ⋮foo: m ⋮m1: t ⋮m2: t ⋮m3: t ⋮m5: t + ⋮m7: t ⋮ok_double_macro_use_shadow: v ⋮ + ⋮crate::m7 + ⋮baz: m + ⋮ ⋮crate::m1 ⋮bar: m ⋮ 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() { ); } +#[test] +fn infer_textual_scoped_macros_expanded() { + assert_snapshot!( + infer(r#" +struct Foo(Vec); + +#[macro_use] +mod m { + macro_rules! foo { + ($($item:expr),*) => { + { + Foo(vec![$($item,)*]) + } + }; + } +} + +fn main() { + let x = foo!(1,2); + let y = crate::foo!(1,2); +} +"#), + @r###" + ![0; 17) '{Foo(v...,2,])}': Foo + ![1; 4) 'Foo': Foo({unknown}) -> Foo + ![1; 16) 'Foo(vec![1,2,])': Foo + ![5; 15) 'vec![1,2,]': {unknown} + [195; 251) '{ ...,2); }': () + [205; 206) 'x': Foo + [228; 229) 'y': {unknown} + [232; 248) 'crate:...!(1,2)': {unknown} + "### + ); +} + #[ignore] #[test] fn method_resolution_trait_before_autoref() { -- cgit v1.2.3