]> git.lizzy.rs Git - rust.git/commitdiff
Resolve textual scoped macros inside item
authoruHOOCCOOHu <hooccooh1896@gmail.com>
Fri, 6 Sep 2019 18:44:26 +0000 (02:44 +0800)
committeruHOOCCOOHu <hooccooh1896@gmail.com>
Sun, 8 Sep 2019 17:34:53 +0000 (01:34 +0800)
crates/ra_hir/src/nameres.rs
crates/ra_hir/src/nameres/collector.rs
crates/ra_hir/src/nameres/tests/macros.rs
crates/ra_hir/src/ty/tests.rs

index e6bf0e90c978e506a9ef4bbee6d5a1efd911541f..befbb2a9b3d6cbd19e4d6f049df71bbdd7753ddf 100644 (file)
@@ -489,16 +489,21 @@ fn resolve_name_in_module_with_macro(
         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<ModuleDef> {
index f897547e39c160eb4c5dbb15dec7d5b7f268caa2..10c32ffa1c4beea8dd9e256e43fcc5a9f8604249 100644 (file)
@@ -14,8 +14,8 @@
         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 @@ fn define_macro(
     /// 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 @@ fn collect_macro(&mut self, mac: &raw::MacroData) {
             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) {
index 8f0db95f23fa18880bad25e479871bcd3f3e179e..a894c68361798bdc95fcc27fb0b9b5409b6cdf0e 100644 (file)
@@ -279,7 +279,7 @@ macro_rules! declare_mod {
 }
 
 #[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 @@ macro_rules! foo {
         }
         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 @@ macro_rules! bar {
     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
    ⋮
index c4bddde85d00de59351bd24bd85ea35ae1dd8004..f2d5b115e10ef1da4b195da44314c04f4534afd4 100644 (file)
@@ -2803,6 +2803,41 @@ fn main() {
     );
 }
 
+#[test]
+fn infer_textual_scoped_macros_expanded() {
+    assert_snapshot!(
+        infer(r#"
+struct Foo(Vec<i32>);
+
+#[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() {