Skip to content

Commit c31c324

Browse files
Basic support for decl macros 2.0
1 parent bd4c352 commit c31c324

File tree

15 files changed

+195
-28
lines changed

15 files changed

+195
-28
lines changed

Cargo.lock

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
2626
# chalk-ir = { path = "../chalk/chalk-ir" }
2727
# chalk-recursive = { path = "../chalk/chalk-recursive" }
2828

29-
# ungrammar = { path = "../ungrammar" }
29+
ungrammar = { path = "../ungrammar" }

crates/hir/src/has_source.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ impl HasSource for TypeAlias {
110110
}
111111
}
112112
impl HasSource for MacroDef {
113-
type Ast = ast::MacroRules;
114-
fn source(self, db: &dyn HirDatabase) -> InFile<ast::MacroRules> {
113+
type Ast = ast::Macro;
114+
fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> {
115115
InFile {
116116
file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
117117
value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()),

crates/hir/src/semantics/source_to_def.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl SourceToDefCtx<'_, '_> {
157157
let file_id = src.file_id.original_file(self.db.upcast());
158158
let krate = self.file_to_def(file_id)?.krate;
159159
let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
160-
let ast_id = Some(AstId::new(src.file_id, file_ast_id));
160+
let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
161161
Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false })
162162
}
163163

crates/hir_def/src/body/lower.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,10 @@ impl ExprCollector<'_> {
772772
| ast::Item::Module(_)
773773
| ast::Item::MacroCall(_) => return None,
774774
ast::Item::MacroRules(def) => {
775-
return Some(Either::Right(def));
775+
return Some(Either::Right(ast::Macro::from(def)));
776+
}
777+
ast::Item::MacroDef(def) => {
778+
return Some(Either::Right(ast::Macro::from(def)));
776779
}
777780
};
778781

crates/hir_def/src/item_tree.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ impl ItemTree {
143143
mods,
144144
macro_calls,
145145
macro_rules,
146+
macro_defs,
146147
exprs,
147148
vis,
148149
generics,
@@ -164,6 +165,7 @@ impl ItemTree {
164165
mods.shrink_to_fit();
165166
macro_calls.shrink_to_fit();
166167
macro_rules.shrink_to_fit();
168+
macro_defs.shrink_to_fit();
167169
exprs.shrink_to_fit();
168170

169171
vis.arena.shrink_to_fit();
@@ -283,6 +285,7 @@ struct ItemTreeData {
283285
mods: Arena<Mod>,
284286
macro_calls: Arena<MacroCall>,
285287
macro_rules: Arena<MacroRules>,
288+
macro_defs: Arena<MacroDef>,
286289
exprs: Arena<Expr>,
287290

288291
vis: ItemVisibilities,
@@ -431,6 +434,7 @@ mod_items! {
431434
Mod in mods -> ast::Module,
432435
MacroCall in macro_calls -> ast::MacroCall,
433436
MacroRules in macro_rules -> ast::MacroRules,
437+
MacroDef in macro_defs -> ast::MacroDef,
434438
}
435439

436440
macro_rules! impl_index {
@@ -640,7 +644,7 @@ pub struct MacroCall {
640644

641645
#[derive(Debug, Clone, Eq, PartialEq)]
642646
pub struct MacroRules {
643-
/// For `macro_rules!` declarations, this is the name of the declared macro.
647+
/// The name of the declared macro.
644648
pub name: Name,
645649
/// Has `#[macro_export]`.
646650
pub is_export: bool,
@@ -651,6 +655,16 @@ pub struct MacroRules {
651655
pub ast_id: FileAstId<ast::MacroRules>,
652656
}
653657

658+
/// "Macros 2.0" macro definition.
659+
#[derive(Debug, Clone, Eq, PartialEq)]
660+
pub struct MacroDef {
661+
pub name: Name,
662+
pub visibility: RawVisibilityId,
663+
/// Has `#[rustc_builtin_macro]`.
664+
pub is_builtin: bool,
665+
pub ast_id: FileAstId<ast::MacroDef>,
666+
}
667+
654668
// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
655669
// lengths, but we don't do much with them yet.
656670
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -680,7 +694,8 @@ impl ModItem {
680694
| ModItem::Trait(_)
681695
| ModItem::Impl(_)
682696
| ModItem::Mod(_)
683-
| ModItem::MacroRules(_) => None,
697+
| ModItem::MacroRules(_)
698+
| ModItem::MacroDef(_) => None,
684699
ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
685700
ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
686701
ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
@@ -708,6 +723,7 @@ impl ModItem {
708723
ModItem::Mod(it) => tree[it.index].ast_id().upcast(),
709724
ModItem::MacroCall(it) => tree[it.index].ast_id().upcast(),
710725
ModItem::MacroRules(it) => tree[it.index].ast_id().upcast(),
726+
ModItem::MacroDef(it) => tree[it.index].ast_id().upcast(),
711727
}
712728
}
713729
}

crates/hir_def/src/item_tree/lower.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ impl Ctx {
101101
| ast::Item::ExternCrate(_)
102102
| ast::Item::Use(_)
103103
| ast::Item::MacroCall(_)
104-
| ast::Item::MacroRules(_) => {}
104+
| ast::Item::MacroRules(_)
105+
| ast::Item::MacroDef(_) => {}
105106
};
106107

107108
let attrs = Attrs::new(item, &self.hygiene);
@@ -122,6 +123,7 @@ impl Ctx {
122123
ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into),
123124
ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
124125
ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
126+
ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
125127
ast::Item::ExternBlock(ast) => {
126128
Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
127129
}
@@ -561,6 +563,18 @@ impl Ctx {
561563
Some(id(self.data().macro_rules.alloc(res)))
562564
}
563565

566+
fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<MacroDef>> {
567+
let name = m.name().map(|it| it.as_name())?;
568+
let attrs = Attrs::new(m, &self.hygiene);
569+
570+
let ast_id = self.source_ast_id_map.ast_id(m);
571+
let visibility = self.lower_visibility(m);
572+
573+
let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
574+
let res = MacroDef { name, is_builtin, ast_id, visibility };
575+
Some(id(self.data().macro_defs.alloc(res)))
576+
}
577+
564578
fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
565579
block.extern_item_list().map_or(Vec::new(), |list| {
566580
list.extern_items()

crates/hir_def/src/nameres/collector.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,33 @@ impl ModCollector<'_, '_> {
976976
}
977977
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
978978
ModItem::MacroRules(mac) => self.collect_macro_rules(&self.item_tree[mac]),
979+
ModItem::MacroDef(id) => {
980+
let mac = &self.item_tree[id];
981+
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
982+
983+
// "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
984+
// to define builtin macros, so we support at least that part.
985+
if mac.is_builtin {
986+
let krate = self.def_collector.def_map.krate;
987+
if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) {
988+
let vis = self
989+
.def_collector
990+
.def_map
991+
.resolve_visibility(
992+
self.def_collector.db,
993+
self.module_id,
994+
&self.item_tree[mac.visibility],
995+
)
996+
.unwrap_or(Visibility::Public);
997+
self.def_collector.update(
998+
self.module_id,
999+
&[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))],
1000+
vis,
1001+
ImportType::Named,
1002+
);
1003+
}
1004+
}
1005+
}
9791006
ModItem::Impl(imp) => {
9801007
let module = ModuleId {
9811008
krate: self.def_collector.def_map.krate,
@@ -1280,7 +1307,7 @@ impl ModCollector<'_, '_> {
12801307
}
12811308

12821309
fn collect_macro_rules(&mut self, mac: &MacroRules) {
1283-
let ast_id = InFile::new(self.file_id, mac.ast_id);
1310+
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
12841311

12851312
// Case 1: builtin macros
12861313
if mac.is_builtin {

crates/hir_expand/src/builtin_macro.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ macro_rules! register_builtin {
6363
pub fn find_builtin_macro(
6464
ident: &name::Name,
6565
krate: CrateId,
66-
ast_id: AstId<ast::MacroRules>,
66+
ast_id: AstId<ast::Macro>,
6767
) -> Option<MacroDefId> {
6868
let kind = find_by_name(ident)?;
6969

@@ -515,24 +515,27 @@ mod tests {
515515
fn expand_builtin_macro(ra_fixture: &str) -> String {
516516
let (db, file_id) = TestDB::with_single_file(&ra_fixture);
517517
let parsed = db.parse(file_id);
518-
let macro_rules: Vec<_> =
518+
let mut macro_rules: Vec<_> =
519519
parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect();
520-
let macro_calls: Vec<_> =
520+
let mut macro_calls: Vec<_> =
521521
parsed.syntax_node().descendants().filter_map(ast::MacroCall::cast).collect();
522522

523523
let ast_id_map = db.ast_id_map(file_id.into());
524524

525525
assert_eq!(macro_rules.len(), 1, "test must contain exactly 1 `macro_rules!`");
526526
assert_eq!(macro_calls.len(), 1, "test must contain exactly 1 macro call");
527-
let expander = find_by_name(&macro_rules[0].name().unwrap().as_name()).unwrap();
527+
let macro_rules = ast::Macro::from(macro_rules.pop().unwrap());
528+
let macro_call = macro_calls.pop().unwrap();
529+
530+
let expander = find_by_name(&macro_rules.name().unwrap().as_name()).unwrap();
528531

529532
let krate = CrateId(0);
530533
let file_id = match expander {
531534
Either::Left(expander) => {
532535
// the first one should be a macro_rules
533536
let def = MacroDefId {
534537
krate: Some(CrateId(0)),
535-
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules[0]))),
538+
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
536539
kind: MacroDefKind::BuiltIn(expander),
537540
local_inner: false,
538541
};
@@ -542,7 +545,7 @@ mod tests {
542545
krate,
543546
kind: MacroCallKind::FnLike(AstId::new(
544547
file_id.into(),
545-
ast_id_map.ast_id(&macro_calls[0]),
548+
ast_id_map.ast_id(&macro_call),
546549
)),
547550
};
548551

@@ -553,12 +556,12 @@ mod tests {
553556
// the first one should be a macro_rules
554557
let def = MacroDefId {
555558
krate: Some(krate),
556-
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules[0]))),
559+
ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
557560
kind: MacroDefKind::BuiltInEager(expander),
558561
local_inner: false,
559562
};
560563

561-
let args = macro_calls[0].token_tree().unwrap();
564+
let args = macro_call.token_tree().unwrap();
562565
let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0;
563566

564567
let arg_id = db.intern_eager_expansion({

crates/hir_expand/src/db.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
129129
fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
130130
match id.kind {
131131
MacroDefKind::Declarative => {
132-
let macro_call = id.ast_id?.to_node(db);
132+
let macro_call = match id.ast_id?.to_node(db) {
133+
syntax::ast::Macro::MacroRules(mac) => mac,
134+
syntax::ast::Macro::MacroDef(_) => return None,
135+
};
133136
let arg = macro_call.token_tree()?;
134137
let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
135138
log::warn!("fail on macro_def to token tree: {:#?}", arg);

0 commit comments

Comments
 (0)