]> git.lizzy.rs Git - rust.git/commitdiff
Support local_inner_macros
authorEdwin Cheng <edwin0cheng@gmail.com>
Fri, 1 May 2020 03:23:03 +0000 (11:23 +0800)
committerEdwin Cheng <edwin0cheng@gmail.com>
Fri, 1 May 2020 03:23:03 +0000 (11:23 +0800)
crates/ra_hir/src/semantics/source_to_def.rs
crates/ra_hir_def/src/body/lower.rs
crates/ra_hir_def/src/nameres/collector.rs
crates/ra_hir_def/src/nameres/raw.rs
crates/ra_hir_def/src/path/lower.rs
crates/ra_hir_expand/src/builtin_derive.rs
crates/ra_hir_expand/src/builtin_macro.rs
crates/ra_hir_expand/src/hygiene.rs
crates/ra_hir_expand/src/lib.rs
crates/ra_hir_ty/src/tests/macros.rs

index 6f3b5b2da8695d49a7bd7d41f8dfc4f7441968c8..8af64fdc1b2583104ff3cc305bfdc74da502bf11 100644 (file)
@@ -151,7 +151,7 @@ pub(super) fn macro_call_to_def(&mut self, src: InFile<ast::MacroCall>) -> Optio
         let krate = self.file_to_def(file_id)?.krate;
         let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
         let ast_id = Some(AstId::new(src.file_id, file_ast_id));
-        Some(MacroDefId { krate: Some(krate), ast_id, kind })
+        Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false })
     }
 
     pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
index f467ed3fe2fe550dd8dc2828d021253af4c0366f..8c1aefbf5c6e087518dee0ec2dd21396ce86378d 100644 (file)
@@ -430,6 +430,7 @@ fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
                         krate: Some(self.expander.module.krate),
                         ast_id: Some(self.expander.ast_id(&e)),
                         kind: MacroDefKind::Declarative,
+                        local_inner: false,
                     };
                     self.body.item_scope.define_legacy_macro(name, mac);
 
index 98c74fe257b4bab593adbd5e0def01663cd4e4ea..bf3968bd62ac04366ff86f2080bc2c5a7ac7111d 100644 (file)
@@ -204,6 +204,7 @@ fn collect_proc_macro(&mut self) {
                 ast_id: None,
                 krate: Some(krate),
                 kind: MacroDefKind::CustomDerive(expander),
+                local_inner: false,
             };
 
             self.define_proc_macro(name.clone(), macro_id);
@@ -941,6 +942,7 @@ fn collect_macro(&mut self, mac: &raw::MacroData) {
                     ast_id: Some(ast_id.ast_id),
                     krate: Some(self.def_collector.def_map.krate),
                     kind: MacroDefKind::Declarative,
+                    local_inner: mac.local_inner,
                 };
                 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
             }
index 39b011ad724c53c08e1c7aea56c9bb803553a22e..aed9dcc72c1db67cb6dd4d0202e5e9f4b6d9352e 100644 (file)
@@ -188,6 +188,7 @@ pub(super) struct MacroData {
     pub(super) path: ModPath,
     pub(super) name: Option<Name>,
     pub(super) export: bool,
+    pub(super) local_inner: bool,
     pub(super) builtin: bool,
 }
 
@@ -401,14 +402,28 @@ fn add_macro(&mut self, current_module: Option<Idx<ModuleData>>, m: ast::MacroCa
 
         let name = m.name().map(|it| it.as_name());
         let ast_id = self.source_ast_id_map.ast_id(&m);
-        // FIXME: cfg_attr
-        let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export");
 
         // FIXME: cfg_attr
-        let builtin =
-            m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro");
-
-        let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin });
+        let export = attrs.by_key("macro_export").exists();
+        let local_inner =
+            attrs.by_key("macro_export").tt_values().map(|it| &it.token_trees).flatten().any(
+                |it| match it {
+                    tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
+                        ident.text.contains("local_inner_macros")
+                    }
+                    _ => false,
+                },
+            );
+        let builtin = attrs.by_key("rustc_builtin_macro").exists();
+
+        let m = self.raw_items.macros.alloc(MacroData {
+            ast_id,
+            path,
+            name,
+            export,
+            local_inner,
+            builtin,
+        });
         self.push_item(current_module, attrs, RawItemKind::Macro(m));
     }
 
index 9ec2e0dcdf01ca5bf7bce26eef39ac1c61a4761f..e632f1afb712accecc31ddcac20f9b54e4c77f09 100644 (file)
@@ -9,7 +9,10 @@
     hygiene::Hygiene,
     name::{name, AsName},
 };
-use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner};
+use ra_syntax::{
+    ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner},
+    T,
+};
 
 use super::AssociatedTypeBinding;
 use crate::{
@@ -113,6 +116,20 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
     }
     segments.reverse();
     generic_args.reverse();
+
+    // handle local_inner_macros :
+    // Basically, even in rustc it is quite hacky:
+    // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456
+    // We follow what it did anyway :)
+    if segments.len() == 1 && kind == PathKind::Plain {
+        let next = path.syntax().last_token().and_then(|it| it.next_token());
+        if next.map_or(false, |it| it.kind() == T![!]) {
+            if let Some(crate_id) = hygiene.local_inner_macros() {
+                kind = PathKind::DollarCrate(crate_id);
+            }
+        }
+    }
+
     let mod_path = ModPath { kind, segments };
     return Some(Path { type_anchor, mod_path, generic_args });
 
index e60f879a393548b4de21c06d261c064ac373e10e..25bb5cee39395ae102e4d0c26e90e5f7ad6f7a50 100644 (file)
@@ -38,7 +38,7 @@ pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
                  _ => return None,
             };
 
-            Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) })
+            Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind),local_inner:false })
         }
     };
 }
index e0fef613db0193e08eaa3ade49788970e681dc5b..d8b3d342ce3a3b4a4a85de03cc47c21281e3cee4 100644 (file)
@@ -73,11 +73,13 @@ pub fn find_builtin_macro(
             krate: Some(krate),
             ast_id: Some(ast_id),
             kind: MacroDefKind::BuiltIn(kind),
+            local_inner: false,
         }),
         Either::Right(kind) => Some(MacroDefId {
             krate: Some(krate),
             ast_id: Some(ast_id),
             kind: MacroDefKind::BuiltInEager(kind),
+            local_inner: false,
         }),
     }
 }
@@ -406,6 +408,7 @@ fn expand_builtin_macro(ra_fixture: &str) -> String {
                     krate: Some(CrateId(0)),
                     ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
                     kind: MacroDefKind::BuiltIn(expander),
+                    local_inner: false,
                 };
 
                 let loc = MacroCallLoc {
@@ -425,6 +428,7 @@ fn expand_builtin_macro(ra_fixture: &str) -> String {
                     krate: Some(CrateId(0)),
                     ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
                     kind: MacroDefKind::BuiltInEager(expander),
+                    local_inner: false,
                 };
 
                 let args = macro_calls[1].token_tree().unwrap();
index 0b41d0e95810bc1718baa49d3b3c238fd579c0b9..3da93de2172df4a4037d3fbf9242514eca7d5c6f 100644 (file)
 pub struct Hygiene {
     // This is what `$crate` expands to
     def_crate: Option<CrateId>,
+
+    // Indiciate this is a local inner macro
+    local_inner: bool,
 }
 
 impl Hygiene {
     pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
-        let def_crate = match file_id.0 {
-            HirFileIdRepr::FileId(_) => None,
+        let (def_crate, local_inner) = match file_id.0 {
+            HirFileIdRepr::FileId(_) => (None, false),
             HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
                 MacroCallId::LazyMacro(id) => {
                     let loc = db.lookup_intern_macro(id);
                     match loc.def.kind {
-                        MacroDefKind::Declarative => loc.def.krate,
-                        MacroDefKind::BuiltIn(_) => None,
-                        MacroDefKind::BuiltInDerive(_) => None,
-                        MacroDefKind::BuiltInEager(_) => None,
-                        MacroDefKind::CustomDerive(_) => None,
+                        MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner),
+                        MacroDefKind::BuiltIn(_) => (None, false),
+                        MacroDefKind::BuiltInDerive(_) => (None, false),
+                        MacroDefKind::BuiltInEager(_) => (None, false),
+                        MacroDefKind::CustomDerive(_) => (None, false),
                     }
                 }
-                MacroCallId::EagerMacro(_id) => None,
+                MacroCallId::EagerMacro(_id) => (None, false),
             },
         };
-        Hygiene { def_crate }
+        Hygiene { def_crate, local_inner }
     }
 
     pub fn new_unhygienic() -> Hygiene {
-        Hygiene { def_crate: None }
+        Hygiene { def_crate: None, local_inner: false }
     }
 
     // FIXME: this should just return name
@@ -52,4 +55,12 @@ pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId>
         }
         Either::Left(name_ref.as_name())
     }
+
+    pub fn local_inner_macros(&self) -> Option<CrateId> {
+        if self.local_inner {
+            self.def_crate
+        } else {
+            None
+        }
+    }
 }
index 754a0f005bae26f766929fc4e8645a89a83c0037..f440c073ba8abd6ebedc28a4e5374a3e8d6126e9 100644 (file)
@@ -204,6 +204,8 @@ pub struct MacroDefId {
     pub krate: Option<CrateId>,
     pub ast_id: Option<AstId<ast::MacroCall>>,
     pub kind: MacroDefKind,
+
+    pub local_inner: bool,
 }
 
 impl MacroDefId {
index 5ddecbdc6808bb728402d565f7a07c5e5ae03dc7..70e17bc9428becad1c2c6c67916816c43ef86689 100644 (file)
@@ -387,6 +387,32 @@ macro_rules! foo {
     );
 }
 
+#[test]
+fn infer_local_inner_macros() {
+    let (db, pos) = TestDB::with_position(
+        r#"
+//- /main.rs crate:main deps:foo
+fn test() {
+    let x = foo::foo!(1);
+    x<|>;
+}
+
+//- /lib.rs crate:foo
+#[macro_export(local_inner_macros)]
+macro_rules! foo {
+    (1) => { bar!() };
+}
+
+#[macro_export]
+macro_rules! bar {
+    () => { 42 }
+}
+
+"#,
+    );
+    assert_eq!("i32", type_at_pos(&db, pos));
+}
+
 #[test]
 fn infer_builtin_macros_line() {
     assert_snapshot!(