From c31c3246a8c87a3639623c30b692a57e728bb046 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Dec 2020 18:43:19 +0100 Subject: Basic support for decl macros 2.0 --- crates/hir_def/src/body/lower.rs | 5 ++++- crates/hir_def/src/item_tree.rs | 20 ++++++++++++++++++-- crates/hir_def/src/item_tree/lower.rs | 16 +++++++++++++++- crates/hir_def/src/nameres/collector.rs | 29 ++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 5 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index bdba4c33e..e4bf5603c 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -772,7 +772,10 @@ impl ExprCollector<'_> { | ast::Item::Module(_) | ast::Item::MacroCall(_) => return None, ast::Item::MacroRules(def) => { - return Some(Either::Right(def)); + return Some(Either::Right(ast::Macro::from(def))); + } + ast::Item::MacroDef(def) => { + return Some(Either::Right(ast::Macro::from(def))); } }; diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 1c9babf37..8cd0b18cc 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -143,6 +143,7 @@ impl ItemTree { mods, macro_calls, macro_rules, + macro_defs, exprs, vis, generics, @@ -164,6 +165,7 @@ impl ItemTree { mods.shrink_to_fit(); macro_calls.shrink_to_fit(); macro_rules.shrink_to_fit(); + macro_defs.shrink_to_fit(); exprs.shrink_to_fit(); vis.arena.shrink_to_fit(); @@ -283,6 +285,7 @@ struct ItemTreeData { mods: Arena, macro_calls: Arena, macro_rules: Arena, + macro_defs: Arena, exprs: Arena, vis: ItemVisibilities, @@ -431,6 +434,7 @@ mod_items! { Mod in mods -> ast::Module, MacroCall in macro_calls -> ast::MacroCall, MacroRules in macro_rules -> ast::MacroRules, + MacroDef in macro_defs -> ast::MacroDef, } macro_rules! impl_index { @@ -640,7 +644,7 @@ pub struct MacroCall { #[derive(Debug, Clone, Eq, PartialEq)] pub struct MacroRules { - /// For `macro_rules!` declarations, this is the name of the declared macro. + /// The name of the declared macro. pub name: Name, /// Has `#[macro_export]`. pub is_export: bool, @@ -651,6 +655,16 @@ pub struct MacroRules { pub ast_id: FileAstId, } +/// "Macros 2.0" macro definition. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MacroDef { + pub name: Name, + pub visibility: RawVisibilityId, + /// Has `#[rustc_builtin_macro]`. + pub is_builtin: bool, + pub ast_id: FileAstId, +} + // NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array // lengths, but we don't do much with them yet. #[derive(Debug, Clone, Eq, PartialEq)] @@ -680,7 +694,8 @@ impl ModItem { | ModItem::Trait(_) | ModItem::Impl(_) | ModItem::Mod(_) - | ModItem::MacroRules(_) => None, + | ModItem::MacroRules(_) + | ModItem::MacroDef(_) => None, ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)), ModItem::Const(konst) => Some(AssocItem::Const(*konst)), ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)), @@ -708,6 +723,7 @@ impl ModItem { ModItem::Mod(it) => tree[it.index].ast_id().upcast(), ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(), ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(), + ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(), } } } diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index b39d7fb7a..1dc06a211 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -101,7 +101,8 @@ impl Ctx { | ast::Item::ExternCrate(_) | ast::Item::Use(_) | ast::Item::MacroCall(_) - | ast::Item::MacroRules(_) => {} + | ast::Item::MacroRules(_) + | ast::Item::MacroDef(_) => {} }; let attrs = Attrs::new(item, &self.hygiene); @@ -122,6 +123,7 @@ impl Ctx { ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), + ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), ast::Item::ExternBlock(ast) => { Some(ModItems(self.lower_extern_block(ast).into_iter().collect::>())) } @@ -561,6 +563,18 @@ impl Ctx { Some(id(self.data().macro_rules.alloc(res))) } + fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option> { + let name = m.name().map(|it| it.as_name())?; + let attrs = Attrs::new(m, &self.hygiene); + + let ast_id = self.source_ast_id_map.ast_id(m); + let visibility = self.lower_visibility(m); + + let is_builtin = attrs.by_key("rustc_builtin_macro").exists(); + let res = MacroDef { name, is_builtin, ast_id, visibility }; + Some(id(self.data().macro_defs.alloc(res))) + } + fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec { block.extern_item_list().map_or(Vec::new(), |list| { list.extern_items() diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 85cc342c4..c2f741060 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -976,6 +976,33 @@ impl ModCollector<'_, '_> { } ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]), + ModItem::MacroDef(id) => { + let mac = &self.item_tree[id]; + let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); + + // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it + // to define builtin macros, so we support at least that part. + if mac.is_builtin { + let krate = self.def_collector.def_map.krate; + if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { + let vis = self + .def_collector + .def_map + .resolve_visibility( + self.def_collector.db, + self.module_id, + &self.item_tree[mac.visibility], + ) + .unwrap_or(Visibility::Public); + self.def_collector.update( + self.module_id, + &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))], + vis, + ImportType::Named, + ); + } + } + } ModItem::Impl(imp) => { let module = ModuleId { krate: self.def_collector.def_map.krate, @@ -1280,7 +1307,7 @@ impl ModCollector<'_, '_> { } fn collect_macro_rules(&mut self, mac: &MacroRules) { - let ast_id = InFile::new(self.file_id, mac.ast_id); + let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); // Case 1: builtin macros if mac.is_builtin { -- cgit v1.2.3 From b238ddd21adf9910769522a21e31c2e14f664396 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Dec 2020 20:33:05 +0100 Subject: Make macro def krate mandatory Refactors builtin derive support to go through proper name resolution --- crates/hir_def/src/body/lower.rs | 2 +- crates/hir_def/src/item_scope.rs | 2 +- crates/hir_def/src/nameres/collector.rs | 18 ++++++----------- crates/hir_def/src/nameres/tests/macros.rs | 31 +++++++++++++++++++++++++++++- 4 files changed, 38 insertions(+), 15 deletions(-) (limited to 'crates/hir_def') diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index e4bf5603c..23e2fd764 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -803,7 +803,7 @@ impl ExprCollector<'_> { } Either::Right(e) => { let mac = MacroDefId { - krate: Some(self.expander.module.krate), + krate: self.expander.module.krate, ast_id: Some(self.expander.ast_id(&e)), kind: MacroDefKind::Declarative, local_inner: false, diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index a8b3fe844..62ab3b2bd 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs @@ -363,7 +363,7 @@ impl ItemInNs { ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db).krate, ModuleDefId::BuiltinType(_) => return None, }, - ItemInNs::Macros(id) => return id.krate, + ItemInNs::Macros(id) => return Some(id.krate), }) } } diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index c2f741060..785895277 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -309,13 +309,13 @@ impl DefCollector<'_> { let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) { Some((_, expander)) => MacroDefId { ast_id: None, - krate: Some(self.def_map.krate), + krate: self.def_map.krate, kind: MacroDefKind::ProcMacro(*expander), local_inner: false, }, None => MacroDefId { ast_id: None, - krate: Some(self.def_map.krate), + krate: self.def_map.krate, kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)), local_inner: false, }, @@ -784,14 +784,6 @@ impl DefCollector<'_> { directive: &DeriveDirective, path: &ModPath, ) -> Option { - if let Some(name) = path.as_ident() { - // FIXME this should actually be handled with the normal name - // resolution; the std lib defines built-in stubs for the derives, - // but these are new-style `macro`s, which we don't support yet - if let Some(def_id) = find_builtin_derive(name) { - return Some(def_id); - } - } let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, ResolveMode::Other, @@ -984,7 +976,9 @@ impl ModCollector<'_, '_> { // to define builtin macros, so we support at least that part. if mac.is_builtin { let krate = self.def_collector.def_map.krate; - if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { + let macro_id = find_builtin_macro(&mac.name, krate, ast_id) + .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); + if let Some(macro_id) = macro_id { let vis = self .def_collector .def_map @@ -1326,7 +1320,7 @@ impl ModCollector<'_, '_> { // Case 2: normal `macro_rules!` macro let macro_id = MacroDefId { ast_id: Some(ast_id), - krate: Some(self.def_collector.def_map.krate), + krate: self.def_collector.def_map.krate, kind: MacroDefKind::Declarative, local_inner: mac.is_local_inner, }; diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 305fca0f9..6fe2ee78a 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs @@ -633,14 +633,43 @@ pub struct bar; fn expand_derive() { let map = compute_crate_def_map( " - //- /main.rs + //- /main.rs crate:main deps:core + use core::*; + #[derive(Copy, Clone)] struct Foo; + + //- /core.rs crate:core + #[rustc_builtin_macro] + pub macro Copy {} + + #[rustc_builtin_macro] + pub macro Clone {} ", ); assert_eq!(map.modules[map.root].scope.impls().len(), 2); } +#[test] +fn resolve_builtin_derive() { + check( + r#" +//- /main.rs crate:main deps:core +use core::*; + +//- /core.rs crate:core +#[rustc_builtin_macro] +pub macro Clone {} + +pub trait Clone {} +"#, + expect![[r#" + crate + Clone: t m + "#]], + ); +} + #[test] fn macro_expansion_overflow() { mark::check!(macro_expansion_overflow); -- cgit v1.2.3