From c31c3246a8c87a3639623c30b692a57e728bb046 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Dec 2020 18:43:19 +0100 Subject: [PATCH 1/3] Basic support for decl macros 2.0 --- Cargo.lock | 2 - Cargo.toml | 2 +- crates/hir/src/has_source.rs | 4 +- crates/hir/src/semantics/source_to_def.rs | 2 +- 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 +++++++++++- crates/hir_expand/src/builtin_macro.rs | 19 ++++---- crates/hir_expand/src/db.rs | 5 ++- crates/hir_expand/src/lib.rs | 7 ++- crates/syntax/src/ast.rs | 4 +- crates/syntax/src/ast/generated/nodes.rs | 36 ++++++++++++++- crates/syntax/src/ast/node_ext.rs | 54 +++++++++++++++++++++++ crates/syntax/src/display.rs | 18 ++++++-- 15 files changed, 195 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff2c33f45d..ff1999ee0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1828,8 +1828,6 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "ungrammar" version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873186a460627379e7e28880a0d33b729c205634f6f021321f50b323235e62d7" [[package]] name = "unicase" diff --git a/Cargo.toml b/Cargo.toml index 59d36fbc1d..fdf2a71a06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,4 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. # chalk-ir = { path = "../chalk/chalk-ir" } # chalk-recursive = { path = "../chalk/chalk-recursive" } -# ungrammar = { path = "../ungrammar" } +ungrammar = { path = "../ungrammar" } diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 107ad06904..ecf3194c6a 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -110,8 +110,8 @@ impl HasSource for TypeAlias { } } impl HasSource for MacroDef { - type Ast = ast::MacroRules; - fn source(self, db: &dyn HirDatabase) -> InFile { + type Ast = ast::Macro; + fn source(self, db: &dyn HirDatabase) -> InFile { InFile { file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()), diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index a333d7aea9..d499ae3402 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -157,7 +157,7 @@ impl SourceToDefCtx<'_, '_> { let file_id = src.file_id.original_file(self.db.upcast()); 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)); + let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast())); Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false }) } diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index bdba4c33ea..e4bf5603c7 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 1c9babf371..8cd0b18ccd 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 b39d7fb7ac..1dc06a2115 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 85cc342c44..c2f741060f 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 { diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index bd92238257..df82cf8e65 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs @@ -63,7 +63,7 @@ macro_rules! register_builtin { pub fn find_builtin_macro( ident: &name::Name, krate: CrateId, - ast_id: AstId, + ast_id: AstId, ) -> Option { let kind = find_by_name(ident)?; @@ -515,16 +515,19 @@ mod tests { fn expand_builtin_macro(ra_fixture: &str) -> String { let (db, file_id) = TestDB::with_single_file(&ra_fixture); let parsed = db.parse(file_id); - let macro_rules: Vec<_> = + let mut macro_rules: Vec<_> = parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect(); - let macro_calls: Vec<_> = + let mut macro_calls: Vec<_> = parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect(); let ast_id_map = db.ast_id_map(file_id.into()); assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`"); assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call"); - let expander = find_by_name(¯o_rules[0].name().unwrap().as_name()).unwrap(); + let macro_rules = ast::Macro::from(macro_rules.pop().unwrap()); + let macro_call = macro_calls.pop().unwrap(); + + let expander = find_by_name(¯o_rules.name().unwrap().as_name()).unwrap(); let krate = CrateId(0); let file_id = match expander { @@ -532,7 +535,7 @@ mod tests { // the first one should be a macro_rules let def = MacroDefId { krate: Some(CrateId(0)), - ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))), + ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), kind: MacroDefKind::BuiltIn(expander), local_inner: false, }; @@ -542,7 +545,7 @@ mod tests { krate, kind: MacroCallKind::FnLike(AstId::new( file_id.into(), - ast_id_map.ast_id(¯o_calls[0]), + ast_id_map.ast_id(¯o_call), )), }; @@ -553,12 +556,12 @@ mod tests { // the first one should be a macro_rules let def = MacroDefId { krate: Some(krate), - ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules[0]))), + ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), kind: MacroDefKind::BuiltInEager(expander), local_inner: false, }; - let args = macro_calls[0].token_tree().unwrap(); + let args = macro_call.token_tree().unwrap(); let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; let arg_id = db.intern_eager_expansion({ diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 11b5b98c87..4477d867f7 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -129,7 +129,10 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc { fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option> { match id.kind { MacroDefKind::Declarative => { - let macro_call = id.ast_id?.to_node(db); + let macro_call = match id.ast_id?.to_node(db) { + syntax::ast::Macro::MacroRules(mac) => mac, + syntax::ast::Macro::MacroDef(_) => return None, + }; let arg = macro_call.token_tree()?; let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { log::warn!("fail on macro_def to token tree: {:#?}", arg); diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index ae3086a95b..55f026c7be 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -145,7 +145,10 @@ impl HirFileId { let arg_tt = loc.kind.arg(db)?; let def = loc.def.ast_id.and_then(|id| { - let def_tt = id.to_node(db).token_tree()?; + let def_tt = match id.to_node(db) { + ast::Macro::MacroRules(mac) => mac.token_tree()?, + ast::Macro::MacroDef(_) => return None, + }; Some(InFile::new(id.file_id, def_tt)) }); @@ -228,7 +231,7 @@ pub struct MacroDefId { // (which will probably require touching this code), we can instead use // that (and also remove the hacks for resolving built-in derives). pub krate: Option, - pub ast_id: Option>, + pub ast_id: Option>, pub kind: MacroDefKind, pub local_inner: bool, diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs index 7844f9ed63..70c568ea1e 100644 --- a/crates/syntax/src/ast.rs +++ b/crates/syntax/src/ast.rs @@ -19,8 +19,8 @@ pub use self::{ expr_ext::{ArrayExprKind, BinOp, Effect, ElseBranch, LiteralKind, PrefixOp, RangeOp}, generated::{nodes::*, tokens::*}, node_ext::{ - AttrKind, FieldKind, NameOrNameRef, PathSegmentKind, SelfParamKind, SlicePatComponents, - StructKind, TypeBoundKind, VisibilityKind, + AttrKind, FieldKind, Macro, NameOrNameRef, PathSegmentKind, SelfParamKind, + SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind, }, token_ext::*, traits::*, diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 0ad75214fc..6eae323f4a 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -286,6 +286,18 @@ impl MacroRules { pub fn token_tree(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct MacroDef { + pub(crate) syntax: SyntaxNode, +} +impl ast::AttrsOwner for MacroDef {} +impl ast::NameOwner for MacroDef {} +impl ast::VisibilityOwner for MacroDef {} +impl MacroDef { + pub fn macro_token(&self) -> Option { support::token(&self.syntax, T![macro]) } + pub fn args(&self) -> Option { support::child(&self.syntax) } + pub fn body(&self) -> Option { support::child(&self.syntax) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Module { pub(crate) syntax: SyntaxNode, } @@ -1332,6 +1344,7 @@ pub enum Item { Impl(Impl), MacroCall(MacroCall), MacroRules(MacroRules), + MacroDef(MacroDef), Module(Module), Static(Static), Struct(Struct), @@ -1689,6 +1702,17 @@ impl AstNode for MacroRules { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for MacroDef { + fn can_cast(kind: SyntaxKind) -> bool { kind == MACRO_DEF } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for Module { fn can_cast(kind: SyntaxKind) -> bool { kind == MODULE } fn cast(syntax: SyntaxNode) -> Option { @@ -3086,6 +3110,9 @@ impl From for Item { impl From for Item { fn from(node: MacroRules) -> Item { Item::MacroRules(node) } } +impl From for Item { + fn from(node: MacroDef) -> Item { Item::MacroDef(node) } +} impl From for Item { fn from(node: Module) -> Item { Item::Module(node) } } @@ -3111,7 +3138,7 @@ impl AstNode for Item { fn can_cast(kind: SyntaxKind) -> bool { match kind { CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES - | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true, + | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true, _ => false, } } @@ -3125,6 +3152,7 @@ impl AstNode for Item { IMPL => Item::Impl(Impl { syntax }), MACRO_CALL => Item::MacroCall(MacroCall { syntax }), MACRO_RULES => Item::MacroRules(MacroRules { syntax }), + MACRO_DEF => Item::MacroDef(MacroDef { syntax }), MODULE => Item::Module(Module { syntax }), STATIC => Item::Static(Static { syntax }), STRUCT => Item::Struct(Struct { syntax }), @@ -3146,6 +3174,7 @@ impl AstNode for Item { Item::Impl(it) => &it.syntax, Item::MacroCall(it) => &it.syntax, Item::MacroRules(it) => &it.syntax, + Item::MacroDef(it) => &it.syntax, Item::Module(it) => &it.syntax, Item::Static(it) => &it.syntax, Item::Struct(it) => &it.syntax, @@ -3615,6 +3644,11 @@ impl std::fmt::Display for MacroRules { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for MacroDef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Module { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index c59a29eab3..40dec3c7f9 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -3,6 +3,7 @@ use std::fmt; +use ast::AttrsOwner; use itertools::Itertools; use parser::SyntaxKind; @@ -31,6 +32,57 @@ fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { node.green().children().next().and_then(|it| it.into_token()).unwrap().text() } +pub enum Macro { + MacroRules(ast::MacroRules), + MacroDef(ast::MacroDef), +} + +impl From for Macro { + fn from(it: ast::MacroRules) -> Self { + Macro::MacroRules(it) + } +} + +impl From for Macro { + fn from(it: ast::MacroDef) -> Self { + Macro::MacroDef(it) + } +} + +impl AstNode for Macro { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + SyntaxKind::MACRO_RULES | SyntaxKind::MACRO_DEF => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + let res = match syntax.kind() { + SyntaxKind::MACRO_RULES => Macro::MacroRules(ast::MacroRules { syntax }), + SyntaxKind::MACRO_DEF => Macro::MacroDef(ast::MacroDef { syntax }), + _ => return None, + }; + Some(res) + } + fn syntax(&self) -> &SyntaxNode { + match self { + Macro::MacroRules(it) => it.syntax(), + Macro::MacroDef(it) => it.syntax(), + } + } +} + +impl NameOwner for Macro { + fn name(&self) -> Option { + match self { + Macro::MacroRules(mac) => mac.name(), + Macro::MacroDef(mac) => mac.name(), + } + } +} + +impl AttrsOwner for Macro {} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum AttrKind { Inner, @@ -462,4 +514,6 @@ impl ast::DocCommentsOwner for ast::Const {} impl ast::DocCommentsOwner for ast::TypeAlias {} impl ast::DocCommentsOwner for ast::Impl {} impl ast::DocCommentsOwner for ast::MacroRules {} +impl ast::DocCommentsOwner for ast::MacroDef {} +impl ast::DocCommentsOwner for ast::Macro {} impl ast::DocCommentsOwner for ast::Use {} diff --git a/crates/syntax/src/display.rs b/crates/syntax/src/display.rs index d33bde30c5..391647fc67 100644 --- a/crates/syntax/src/display.rs +++ b/crates/syntax/src/display.rs @@ -76,8 +76,20 @@ pub fn type_label(node: &ast::TypeAlias) -> String { label.trim().to_owned() } -pub fn macro_label(node: &ast::MacroRules) -> String { +pub fn macro_label(node: &ast::Macro) -> String { let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default(); - let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; - format!("{}macro_rules! {}", vis, name) + match node { + ast::Macro::MacroRules(node) => { + let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" }; + format!("{}macro_rules! {}", vis, name) + } + ast::Macro::MacroDef(node) => { + let mut s = String::new(); + if let Some(vis) = node.visibility() { + format_to!(s, "{} ", vis); + } + format_to!(s, "macro {}", name); + s + } + } } From b238ddd21adf9910769522a21e31c2e14f664396 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Dec 2020 20:33:05 +0100 Subject: [PATCH 2/3] Make macro def krate mandatory Refactors builtin derive support to go through proper name resolution --- crates/hir/src/code_model.rs | 2 +- crates/hir/src/semantics/source_to_def.rs | 2 +- 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 +++++++++++++- crates/hir_expand/src/builtin_derive.rs | 40 ++++++++++++++----- crates/hir_expand/src/builtin_macro.rs | 8 ++-- crates/hir_expand/src/hygiene.rs | 4 +- crates/hir_expand/src/lib.rs | 8 +--- crates/hir_ty/src/tests/macros.rs | 6 +++ crates/ide/src/goto_implementation.rs | 2 + .../test_data/highlighting.html | 5 ++- crates/ide/src/syntax_highlighting/tests.rs | 3 ++ 14 files changed, 91 insertions(+), 42 deletions(-) diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 42dc35b762..9bfcd215a5 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs @@ -970,7 +970,7 @@ impl MacroDef { /// defines this macro. The reasons for this is that macros are expanded /// early, in `hir_expand`, where modules simply do not exist yet. pub fn module(self, db: &dyn HirDatabase) -> Option { - let krate = self.id.krate?; + let krate = self.id.krate; let module_id = db.crate_def_map(krate).root; Some(Module::new(Crate { id: krate }, module_id)) } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index d499ae3402..3efca5baa5 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -158,7 +158,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.upcast())); - Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false }) + Some(MacroDefId { krate, ast_id, kind, local_inner: false }) } pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option { diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index e4bf5603c7..23e2fd7641 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 a8b3fe844a..62ab3b2bd6 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 c2f741060f..785895277f 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 305fca0f9c..6fe2ee78a1 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); diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index 988a60d56a..ad378762a1 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs @@ -8,7 +8,7 @@ use syntax::{ match_ast, }; -use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; +use crate::{db::AstDatabase, name, quote, AstId, CrateId, LazyMacroId, MacroDefId, MacroDefKind}; macro_rules! register_builtin { ( $($trait:ident => $expand:ident),* ) => { @@ -29,16 +29,15 @@ macro_rules! register_builtin { }; expander(db, id, tt) } + + fn find_by_name(name: &name::Name) -> Option { + match name { + $( id if id == &name::name![$trait] => Some(BuiltinDeriveExpander::$trait), )* + _ => None, + } + } } - pub fn find_builtin_derive(ident: &name::Name) -> Option { - let kind = match ident { - $( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )* - _ => return None, - }; - - Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind), local_inner: false }) - } }; } @@ -54,6 +53,20 @@ register_builtin! { PartialEq => partial_eq_expand } +pub fn find_builtin_derive( + ident: &name::Name, + krate: CrateId, + ast_id: AstId, +) -> Option { + let expander = BuiltinDeriveExpander::find_by_name(ident)?; + Some(MacroDefId { + krate, + ast_id: Some(ast_id), + kind: MacroDefKind::BuiltInDerive(expander), + local_inner: false, + }) +} + struct BasicAdtInfo { name: tt::Ident, type_params: usize, @@ -261,7 +274,7 @@ mod tests { use super::*; fn expand_builtin_derive(s: &str, name: Name) -> String { - let def = find_builtin_derive(&name).unwrap(); + let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); let fixture = format!( r#"//- /main.rs crate:main deps:core <|> @@ -283,7 +296,12 @@ mod tests { let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); let loc = MacroCallLoc { - def, + def: MacroDefId { + krate: CrateId(0), + ast_id: None, + kind: MacroDefKind::BuiltInDerive(expander), + local_inner: false, + }, krate: CrateId(0), kind: MacroCallKind::Attr(attr_id, name.to_string()), }; diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index df82cf8e65..dddbbcdac4 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs @@ -69,13 +69,13 @@ pub fn find_builtin_macro( match kind { Either::Left(kind) => Some(MacroDefId { - krate: Some(krate), + krate, ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind), local_inner: false, }), Either::Right(kind) => Some(MacroDefId { - krate: Some(krate), + krate, ast_id: Some(ast_id), kind: MacroDefKind::BuiltInEager(kind), local_inner: false, @@ -534,7 +534,7 @@ mod tests { Either::Left(expander) => { // the first one should be a macro_rules let def = MacroDefId { - krate: Some(CrateId(0)), + krate: CrateId(0), ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), kind: MacroDefKind::BuiltIn(expander), local_inner: false, @@ -555,7 +555,7 @@ mod tests { Either::Right(expander) => { // the first one should be a macro_rules let def = MacroDefId { - krate: Some(krate), + krate, ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_rules))), kind: MacroDefKind::BuiltInEager(expander), local_inner: false, diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 5d3fa0518f..7ab0a5e52e 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs @@ -29,8 +29,8 @@ impl Hygiene { MacroCallId::LazyMacro(id) => { let loc = db.lookup_intern_macro(id); match loc.def.kind { - MacroDefKind::Declarative => (loc.def.krate, loc.def.local_inner), - MacroDefKind::BuiltIn(_) => (loc.def.krate, false), + MacroDefKind::Declarative => (Some(loc.def.krate), loc.def.local_inner), + MacroDefKind::BuiltIn(_) => (Some(loc.def.krate), false), MacroDefKind::BuiltInDerive(_) => (None, false), MacroDefKind::BuiltInEager(_) => (None, false), MacroDefKind::ProcMacro(_) => (None, false), diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 55f026c7be..d486186e59 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -224,13 +224,7 @@ impl From for MacroCallId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { - // FIXME: krate and ast_id are currently optional because we don't have a - // definition location for built-in derives. There is one, though: the - // standard library defines them. The problem is that it uses the new - // `macro` syntax for this, which we don't support yet. As soon as we do - // (which will probably require touching this code), we can instead use - // that (and also remove the hacks for resolving built-in derives). - pub krate: Option, + pub krate: CrateId, pub ast_id: Option>, pub kind: MacroDefKind, diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index de97ec3c20..a7656b8648 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs @@ -686,6 +686,8 @@ mod clone { trait Clone { fn clone(&self) -> Self; } + #[rustc_builtin_macro] + macro Clone {} } "#, ); @@ -702,6 +704,8 @@ mod clone { trait Clone { fn clone(&self) -> Self; } + #[rustc_builtin_macro] + macro Clone {} } #[derive(Clone)] pub struct S; @@ -737,6 +741,8 @@ mod clone { trait Clone { fn clone(&self) -> Self; } + #[rustc_builtin_macro] + macro Clone {} } "#, ); diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 529004878d..68c628d314 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs @@ -221,6 +221,8 @@ struct Foo<|>; mod marker { trait Copy {} } +#[rustc_builtin_macro] +macro Copy {} "#, ); } diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 0569cf1e5a..3530a5fdb4 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html @@ -38,6 +38,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
use inner::{self as inner_mod};
 mod inner {}
 
+#[rustc_builtin_macro]
+macro Copy {}
+
 // Needed for function consuming vs normal
 pub mod marker {
     #[lang = "copy"]
@@ -119,7 +122,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     f()
 }
 
-fn foobar() -> impl Copy {}
+fn foobar() -> impl Copy {}
 
 fn foo() {
     let bar = foobar();
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 1dc018a167..f53d2c3ba4 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -12,6 +12,9 @@ fn test_highlighting() {
 use inner::{self as inner_mod};
 mod inner {}
 
+#[rustc_builtin_macro]
+macro Copy {}
+
 // Needed for function consuming vs normal
 pub mod marker {
     #[lang = "copy"]

From d34611633b3b2404188b9e12b08c5def589808c2 Mon Sep 17 00:00:00 2001
From: Jonas Schievink 
Date: Wed, 16 Dec 2020 12:54:34 +0100
Subject: [PATCH 3/3] Unpatch ungrammar

---
 Cargo.lock | 4 +++-
 Cargo.toml | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index ff1999ee0c..e44b7d1d92 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1827,7 +1827,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
 [[package]]
 name = "ungrammar"
-version = "1.2.2"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7311ee93faac43aa9da26b043eb244092a29a3078c79af9396f63f800cc3a59a"
 
 [[package]]
 name = "unicase"
diff --git a/Cargo.toml b/Cargo.toml
index fdf2a71a06..59d36fbc1d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,4 +26,4 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
 # chalk-ir = { path = "../chalk/chalk-ir" }
 # chalk-recursive = { path = "../chalk/chalk-recursive" }
 
-ungrammar = { path = "../ungrammar" }
+# ungrammar = { path = "../ungrammar" }