From e4267967a8ee3b35d902931cecf06bb4e19f86c5 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 1 May 2020 11:23:03 +0800 Subject: [PATCH 1/5] Support local_inner_macros --- crates/ra_hir/src/semantics/source_to_def.rs | 2 +- crates/ra_hir_def/src/body/lower.rs | 1 + crates/ra_hir_def/src/nameres/collector.rs | 2 ++ crates/ra_hir_def/src/nameres/raw.rs | 25 ++++++++++++---- crates/ra_hir_def/src/path/lower.rs | 19 +++++++++++- crates/ra_hir_expand/src/builtin_derive.rs | 2 +- crates/ra_hir_expand/src/builtin_macro.rs | 4 +++ crates/ra_hir_expand/src/hygiene.rs | 31 +++++++++++++------- crates/ra_hir_expand/src/lib.rs | 2 ++ crates/ra_hir_ty/src/tests/macros.rs | 26 ++++++++++++++++ 10 files changed, 96 insertions(+), 18 deletions(-) diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs index 6f3b5b2da8..8af64fdc1b 100644 --- a/crates/ra_hir/src/semantics/source_to_def.rs +++ b/crates/ra_hir/src/semantics/source_to_def.rs @@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> { 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 { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f467ed3fe2..8c1aefbf5c 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -430,6 +430,7 @@ impl ExprCollector<'_> { 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); diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 98c74fe257..bf3968bd62 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -204,6 +204,7 @@ impl DefCollector<'_> { 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 @@ impl ModCollector<'_, '_> { 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); } diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 39b011ad72..aed9dcc72c 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -188,6 +188,7 @@ pub(super) struct MacroData { pub(super) path: ModPath, pub(super) name: Option, pub(super) export: bool, + pub(super) local_inner: bool, pub(super) builtin: bool, } @@ -401,14 +402,28 @@ impl RawItemsCollector { 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 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, builtin }); + 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)); } diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 9ec2e0dcdf..e632f1afb7 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -9,7 +9,10 @@ use hir_expand::{ 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 } 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 }); diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index e60f879a39..25bb5cee39 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -38,7 +38,7 @@ macro_rules! register_builtin { _ => 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 }) } }; } diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index e0fef613db..d8b3d342ce 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -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 @@ mod tests { krate: Some(CrateId(0)), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), kind: MacroDefKind::BuiltIn(expander), + local_inner: false, }; let loc = MacroCallLoc { @@ -425,6 +428,7 @@ mod tests { krate: Some(CrateId(0)), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), kind: MacroDefKind::BuiltInEager(expander), + local_inner: false, }; let args = macro_calls[1].token_tree().unwrap(); diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 0b41d0e958..3da93de217 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs @@ -16,31 +16,34 @@ use crate::{ pub struct Hygiene { // This is what `$crate` expands to def_crate: Option, + + // 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 @@ impl Hygiene { } Either::Left(name_ref.as_name()) } + + pub fn local_inner_macros(&self) -> Option { + if self.local_inner { + self.def_crate + } else { + None + } + } } diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 754a0f005b..f440c073ba 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -204,6 +204,8 @@ pub struct MacroDefId { pub krate: Option, pub ast_id: Option>, pub kind: MacroDefKind, + + pub local_inner: bool, } impl MacroDefId { diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 5ddecbdc68..70e17bc942 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -387,6 +387,32 @@ fn main() { ); } +#[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!( From 7bbdeb43a4972300779a8d30c7323445c1105f44 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Fri, 1 May 2020 20:58:24 +0800 Subject: [PATCH 2/5] Make AttrQuery copyable --- crates/ra_hir_def/src/attr.rs | 1 + crates/ra_hir_def/src/nameres/raw.rs | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 5a86af8ba3..576cd0c65b 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs @@ -140,6 +140,7 @@ impl Attr { } } +#[derive(Debug, Clone, Copy)] pub struct AttrQuery<'a> { attrs: &'a Attrs, key: &'static str, diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index aed9dcc72c..a71503c76e 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -404,16 +404,20 @@ impl RawItemsCollector { let ast_id = self.source_ast_id_map.ast_id(&m); // FIXME: cfg_attr - 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 export_attr = attrs.by_key("macro_export"); + + let export = export_attr.exists(); + let local_inner = if export { + export_attr.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, + }) + } else { + false + }; + let builtin = attrs.by_key("rustc_builtin_macro").exists(); let m = self.raw_items.macros.alloc(MacroData { From 443762cda914e56487e51ed0e104b3aac7285b1a Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 2 May 2020 09:56:38 +0800 Subject: [PATCH 3/5] Update crates/ra_hir_expand/src/builtin_derive.rs Fix spacing Co-authored-by: Jonas Schievink --- crates/ra_hir_expand/src/builtin_derive.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 25bb5cee39..1dc9cac665 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs @@ -38,7 +38,7 @@ macro_rules! register_builtin { _ => return None, }; - Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind),local_inner:false }) + Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind), local_inner: false }) } }; } From 291d03949bbd1e8f96dcf348e184d91d57204419 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 2 May 2020 10:06:17 +0800 Subject: [PATCH 4/5] Add test in name resolutions --- crates/ra_hir_def/src/nameres/tests/macros.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index b0befdfbd6..9bc0e62874 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs @@ -135,6 +135,43 @@ fn macro_rules_export_with_local_inner_macros_are_visible() { "###); } +#[test] +fn local_inner_macros_makes_local_macros_usable() { + let map = def_map( + " + //- /main.rs crate:main deps:foo + foo::structs!(Foo, Bar); + mod bar; + //- /bar.rs + use crate::*; + //- /lib.rs crate:foo + #[macro_export(local_inner_macros)] + macro_rules! structs { + ($($i:ident),*) => { + inner!($($i),*); + } + } + #[macro_export] + macro_rules! inner { + ($($i:ident),*) => { + $(struct $i { field: u32 } )* + } + } + ", + ); + assert_snapshot!(map, @r###" + ⋮crate + ⋮Bar: t v + ⋮Foo: t v + ⋮bar: t + ⋮ + ⋮crate::bar + ⋮Bar: t v + ⋮Foo: t v + ⋮bar: t + "###); +} + #[test] fn unexpanded_macro_should_expand_by_fixedpoint_loop() { let map = def_map( From edf0b4c1528407d5077220191e601ac41f790b99 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 2 May 2020 10:16:26 +0800 Subject: [PATCH 5/5] Test whether it is bang macro properly --- crates/ra_hir_def/src/path/lower.rs | 14 ++++++-------- crates/ra_syntax/src/ast/extensions.rs | 4 ++++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index e632f1afb7..b902cacd1b 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs @@ -9,10 +9,7 @@ use hir_expand::{ hygiene::Hygiene, name::{name, AsName}, }; -use ra_syntax::{ - ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}, - T, -}; +use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; use super::AssociatedTypeBinding; use crate::{ @@ -122,10 +119,11 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option // 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); + if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { + if macro_call.is_bang() { + if let Some(crate_id) = hygiene.local_inner_macros() { + kind = PathKind::DollarCrate(crate_id); + } } } } diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index f2ea5088e7..d68f1029f1 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs @@ -423,6 +423,10 @@ impl ast::MacroCall { None } } + + pub fn is_bang(&self) -> bool { + self.is_macro_rules().is_none() + } } impl ast::LifetimeParam {