Skip to content

Commit d5f64f8

Browse files
committed
Infallibe ExpandDatabase::macro_def
1 parent 4ff9339 commit d5f64f8

File tree

10 files changed

+215
-164
lines changed

10 files changed

+215
-164
lines changed

crates/hir-def/src/macro_expansion_tests/mod.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use ::mbe::TokenMap;
2020
use base_db::{fixture::WithFixture, ProcMacro, SourceDatabase};
2121
use expect_test::Expect;
2222
use hir_expand::{
23-
db::{ExpandDatabase, TokenExpander},
24-
AstId, InFile, MacroDefId, MacroDefKind, MacroFile,
23+
db::{DeclarativeMacroExpander, ExpandDatabase},
24+
AstId, InFile, MacroFile,
2525
};
2626
use stdx::format_to;
2727
use syntax::{
@@ -100,32 +100,29 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
100100
let call_offset = macro_.syntax().text_range().start().into();
101101
let file_ast_id = db.ast_id_map(source.file_id).ast_id(&macro_);
102102
let ast_id = AstId::new(source.file_id, file_ast_id.upcast());
103-
let kind = MacroDefKind::Declarative(ast_id);
104103

105-
let macro_def = db
106-
.macro_def(MacroDefId { krate, kind, local_inner: false, allow_internal_unsafe: false })
107-
.unwrap();
108-
if let TokenExpander::DeclarativeMacro { mac, def_site_token_map } = &*macro_def {
109-
let tt = match &macro_ {
110-
ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
111-
ast::Macro::MacroDef(_) => unimplemented!(""),
112-
};
104+
let DeclarativeMacroExpander { mac, def_site_token_map } =
105+
&*db.decl_macro_expander(krate, ast_id);
106+
assert_eq!(mac.err(), None);
107+
let tt = match &macro_ {
108+
ast::Macro::MacroRules(mac) => mac.token_tree().unwrap(),
109+
ast::Macro::MacroDef(_) => unimplemented!(""),
110+
};
113111

114-
let tt_start = tt.syntax().text_range().start();
115-
tt.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token).for_each(
116-
|token| {
117-
let range = token.text_range().checked_sub(tt_start).unwrap();
118-
if let Some(id) = def_site_token_map.token_by_range(range) {
119-
let offset = (range.end() + tt_start).into();
120-
text_edits.push((offset..offset, format!("#{}", id.0)));
121-
}
122-
},
123-
);
124-
text_edits.push((
125-
call_offset..call_offset,
126-
format!("// call ids will be shifted by {:?}\n", mac.shift()),
127-
));
128-
}
112+
let tt_start = tt.syntax().text_range().start();
113+
tt.syntax().descendants_with_tokens().filter_map(SyntaxElement::into_token).for_each(
114+
|token| {
115+
let range = token.text_range().checked_sub(tt_start).unwrap();
116+
if let Some(id) = def_site_token_map.token_by_range(range) {
117+
let offset = (range.end() + tt_start).into();
118+
text_edits.push((offset..offset, format!("#{}", id.0)));
119+
}
120+
},
121+
);
122+
text_edits.push((
123+
call_offset..call_offset,
124+
format!("// call ids will be shifted by {:?}\n", mac.shift()),
125+
));
129126
}
130127

131128
for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) {

crates/hir-expand/src/db.rs

Lines changed: 105 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Defines database & queries for macro expansion.
22
3-
use base_db::{salsa, Edition, SourceDatabase};
3+
use base_db::{salsa, CrateId, Edition, SourceDatabase};
44
use either::Either;
55
use limit::Limit;
66
use mbe::syntax_node_to_token_tree;
@@ -13,7 +13,7 @@ use triomphe::Arc;
1313

1414
use crate::{
1515
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion,
16-
builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, BuiltinAttrExpander,
16+
builtin_fn_macro::EagerExpander, fixup, hygiene::HygieneFrame, tt, AstId, BuiltinAttrExpander,
1717
BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo, ExpandError, ExpandResult,
1818
ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId,
1919
MacroDefKind, MacroFile, ProcMacroExpander,
@@ -27,61 +27,59 @@ use crate::{
2727
/// Actual max for `analysis-stats .` at some point: 30672.
2828
static TOKEN_LIMIT: Limit = Limit::new(1_048_576);
2929

30+
#[derive(Debug, Clone, Eq, PartialEq)]
31+
/// Old-style `macro_rules` or the new macros 2.0
32+
pub struct DeclarativeMacroExpander {
33+
pub mac: mbe::DeclarativeMacro,
34+
pub def_site_token_map: mbe::TokenMap,
35+
}
36+
37+
impl DeclarativeMacroExpander {
38+
pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> {
39+
match self.mac.err() {
40+
Some(e) => ExpandResult::new(
41+
tt::Subtree::empty(),
42+
ExpandError::other(format!("invalid macro definition: {e}")),
43+
),
44+
None => self.mac.expand(tt).map_err(Into::into),
45+
}
46+
}
47+
}
48+
3049
#[derive(Debug, Clone, Eq, PartialEq)]
3150
pub enum TokenExpander {
32-
/// Old-style `macro_rules` or the new macros 2.0
33-
DeclarativeMacro { mac: mbe::DeclarativeMacro, def_site_token_map: mbe::TokenMap },
51+
DeclarativeMacro(Arc<DeclarativeMacroExpander>),
3452
/// Stuff like `line!` and `file!`.
35-
Builtin(BuiltinFnLikeExpander),
53+
BuiltIn(BuiltinFnLikeExpander),
3654
/// Built-in eagerly expanded fn-like macros (`include!`, `concat!`, etc.)
37-
BuiltinEager(EagerExpander),
55+
BuiltInEager(EagerExpander),
3856
/// `global_allocator` and such.
39-
BuiltinAttr(BuiltinAttrExpander),
57+
BuiltInAttr(BuiltinAttrExpander),
4058
/// `derive(Copy)` and such.
41-
BuiltinDerive(BuiltinDeriveExpander),
59+
BuiltInDerive(BuiltinDeriveExpander),
4260
/// The thing we love the most here in rust-analyzer -- procedural macros.
4361
ProcMacro(ProcMacroExpander),
4462
}
4563

4664
impl TokenExpander {
47-
fn expand(
48-
&self,
49-
db: &dyn ExpandDatabase,
50-
id: MacroCallId,
51-
tt: &tt::Subtree,
52-
) -> ExpandResult<tt::Subtree> {
53-
match self {
54-
TokenExpander::DeclarativeMacro { mac, .. } => mac.expand(tt).map_err(Into::into),
55-
TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into),
56-
TokenExpander::BuiltinEager(it) => it.expand(db, id, tt).map_err(Into::into),
57-
TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt),
58-
TokenExpander::BuiltinDerive(_) => {
59-
unreachable!("builtin derives should be expanded manually")
60-
}
61-
TokenExpander::ProcMacro(_) => {
62-
unreachable!("ExpandDatabase::expand_proc_macro should be used for proc macros")
63-
}
64-
}
65-
}
66-
6765
pub(crate) fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
6866
match self {
69-
TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_down(id),
70-
TokenExpander::Builtin(..)
71-
| TokenExpander::BuiltinEager(..)
72-
| TokenExpander::BuiltinAttr(..)
73-
| TokenExpander::BuiltinDerive(..)
67+
TokenExpander::DeclarativeMacro(expander) => expander.mac.map_id_down(id),
68+
TokenExpander::BuiltIn(..)
69+
| TokenExpander::BuiltInEager(..)
70+
| TokenExpander::BuiltInAttr(..)
71+
| TokenExpander::BuiltInDerive(..)
7472
| TokenExpander::ProcMacro(..) => id,
7573
}
7674
}
7775

7876
pub(crate) fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
7977
match self {
80-
TokenExpander::DeclarativeMacro { mac, .. } => mac.map_id_up(id),
81-
TokenExpander::Builtin(..)
82-
| TokenExpander::BuiltinEager(..)
83-
| TokenExpander::BuiltinAttr(..)
84-
| TokenExpander::BuiltinDerive(..)
78+
TokenExpander::DeclarativeMacro(expander) => expander.mac.map_id_up(id),
79+
TokenExpander::BuiltIn(..)
80+
| TokenExpander::BuiltInEager(..)
81+
| TokenExpander::BuiltInAttr(..)
82+
| TokenExpander::BuiltInDerive(..)
8583
| TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
8684
}
8785
}
@@ -124,7 +122,14 @@ pub trait ExpandDatabase: SourceDatabase {
124122
fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>;
125123
/// Gets the expander for this macro. This compiles declarative macros, and
126124
/// just fetches procedural ones.
127-
fn macro_def(&self, id: MacroDefId) -> Result<Arc<TokenExpander>, mbe::ParseError>;
125+
// FIXME: Rename this
126+
#[salsa::transparent]
127+
fn macro_def(&self, id: MacroDefId) -> TokenExpander;
128+
fn decl_macro_expander(
129+
&self,
130+
def_crate: CrateId,
131+
id: AstId<ast::Macro>,
132+
) -> Arc<DeclarativeMacroExpander>;
128133

129134
/// Expand macro call to a token tree.
130135
// This query is LRU cached
@@ -162,7 +167,7 @@ pub fn expand_speculative(
162167
token_to_map: SyntaxToken,
163168
) -> Option<(SyntaxNode, SyntaxToken)> {
164169
let loc = db.lookup_intern_macro_call(actual_macro_call);
165-
let macro_def = db.macro_def(loc.def).ok()?;
170+
let macro_def = db.macro_def(loc.def);
166171
let token_range = token_to_map.text_range();
167172

168173
// Build the subtree and token mapping for the speculative args
@@ -239,7 +244,12 @@ pub fn expand_speculative(
239244
let adt = ast::Adt::cast(speculative_args.clone()).unwrap();
240245
expander.expand(db, actual_macro_call, &adt, &spec_args_tmap)
241246
}
242-
_ => macro_def.expand(db, actual_macro_call, &tt),
247+
MacroDefKind::Declarative(it) => db.decl_macro_expander(loc.krate, it).expand(&tt),
248+
MacroDefKind::BuiltIn(it, _) => it.expand(db, actual_macro_call, &tt).map_err(Into::into),
249+
MacroDefKind::BuiltInEager(it, _) => {
250+
it.expand(db, actual_macro_call, &tt).map_err(Into::into)
251+
}
252+
MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt),
243253
};
244254

245255
let expand_to = macro_expand_to(db, actual_macro_call);
@@ -412,44 +422,55 @@ fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode>
412422
}
413423
}
414424

415-
fn macro_def(
425+
fn decl_macro_expander(
416426
db: &dyn ExpandDatabase,
417-
id: MacroDefId,
418-
) -> Result<Arc<TokenExpander>, mbe::ParseError> {
427+
def_crate: CrateId,
428+
id: AstId<ast::Macro>,
429+
) -> Arc<DeclarativeMacroExpander> {
430+
let is_2021 = db.crate_graph()[def_crate].edition >= Edition::Edition2021;
431+
let (mac, def_site_token_map) = match id.to_node(db) {
432+
ast::Macro::MacroRules(macro_rules) => match macro_rules.token_tree() {
433+
Some(arg) => {
434+
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
435+
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021);
436+
(mac, def_site_token_map)
437+
}
438+
None => (
439+
mbe::DeclarativeMacro::from_err(
440+
mbe::ParseError::Expected("expected a token tree".into()),
441+
is_2021,
442+
),
443+
Default::default(),
444+
),
445+
},
446+
ast::Macro::MacroDef(macro_def) => match macro_def.body() {
447+
Some(arg) => {
448+
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
449+
let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021);
450+
(mac, def_site_token_map)
451+
}
452+
None => (
453+
mbe::DeclarativeMacro::from_err(
454+
mbe::ParseError::Expected("expected a token tree".into()),
455+
is_2021,
456+
),
457+
Default::default(),
458+
),
459+
},
460+
};
461+
Arc::new(DeclarativeMacroExpander { mac, def_site_token_map })
462+
}
463+
464+
fn macro_def(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
419465
match id.kind {
420466
MacroDefKind::Declarative(ast_id) => {
421-
let is_2021 = db.crate_graph()[id.krate].edition >= Edition::Edition2021;
422-
let (mac, def_site_token_map) = match ast_id.to_node(db) {
423-
ast::Macro::MacroRules(macro_rules) => {
424-
let arg = macro_rules
425-
.token_tree()
426-
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
427-
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
428-
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021)?;
429-
(mac, def_site_token_map)
430-
}
431-
ast::Macro::MacroDef(macro_def) => {
432-
let arg = macro_def
433-
.body()
434-
.ok_or_else(|| mbe::ParseError::Expected("expected a token tree".into()))?;
435-
let (tt, def_site_token_map) = mbe::syntax_node_to_token_tree(arg.syntax());
436-
let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021)?;
437-
(mac, def_site_token_map)
438-
}
439-
};
440-
Ok(Arc::new(TokenExpander::DeclarativeMacro { mac, def_site_token_map }))
441-
}
442-
MacroDefKind::BuiltIn(expander, _) => Ok(Arc::new(TokenExpander::Builtin(expander))),
443-
MacroDefKind::BuiltInAttr(expander, _) => {
444-
Ok(Arc::new(TokenExpander::BuiltinAttr(expander)))
445-
}
446-
MacroDefKind::BuiltInDerive(expander, _) => {
447-
Ok(Arc::new(TokenExpander::BuiltinDerive(expander)))
448-
}
449-
MacroDefKind::BuiltInEager(expander, ..) => {
450-
Ok(Arc::new(TokenExpander::BuiltinEager(expander)))
467+
TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
451468
}
452-
MacroDefKind::ProcMacro(expander, ..) => Ok(Arc::new(TokenExpander::ProcMacro(expander))),
469+
MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander),
470+
MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander),
471+
MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander),
472+
MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander),
473+
MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander),
453474
}
454475
}
455476

@@ -483,20 +504,6 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
483504
(expander.expand(db, id, &adt, &tmap), Some((tmap, fixups.undo_info)))
484505
}
485506
_ => {
486-
let expander = match db.macro_def(loc.def) {
487-
Ok(it) => it,
488-
// FIXME: We should make sure to enforce a variant that invalid macro
489-
// definitions do not get expanders that could reach this call path!
490-
Err(err) => {
491-
return ExpandResult {
492-
value: Arc::new(tt::Subtree {
493-
delimiter: tt::Delimiter::UNSPECIFIED,
494-
token_trees: vec![],
495-
}),
496-
err: Some(ExpandError::other(format!("invalid macro definition: {err}"))),
497-
}
498-
}
499-
};
500507
let Some(macro_arg) = db.macro_arg(id) else {
501508
return ExpandResult {
502509
value: Arc::new(tt::Subtree {
@@ -509,7 +516,15 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
509516
};
510517
};
511518
let (arg, arg_tm, undo_info) = &*macro_arg;
512-
let mut res = expander.expand(db, id, arg);
519+
let mut res = match loc.def.kind {
520+
MacroDefKind::Declarative(id) => {
521+
db.decl_macro_expander(loc.def.krate, id).expand(&arg)
522+
}
523+
MacroDefKind::BuiltIn(it, _) => it.expand(db, id, &arg).map_err(Into::into),
524+
MacroDefKind::BuiltInEager(it, _) => it.expand(db, id, &arg).map_err(Into::into),
525+
MacroDefKind::BuiltInAttr(it, _) => it.expand(db, id, &arg),
526+
_ => unreachable!(),
527+
};
513528
fixup::reverse_fixups(&mut res.value, arg_tm, undo_info);
514529
(res, None)
515530
}

crates/hir-expand/src/hygiene.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ struct HygieneInfo {
126126
/// The start offset of the `macro_rules!` arguments or attribute input.
127127
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
128128

129-
macro_def: Arc<TokenExpander>,
129+
macro_def: TokenExpander,
130130
macro_arg: Arc<(crate::tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
131131
macro_arg_shift: mbe::Shift,
132132
exp_map: Arc<mbe::TokenMap>,
@@ -159,9 +159,9 @@ impl HygieneInfo {
159159
&self.macro_arg.1,
160160
InFile::new(loc.kind.file_id(), loc.kind.arg(db)?.text_range().start()),
161161
),
162-
mbe::Origin::Def => match (&*self.macro_def, &self.attr_input_or_mac_def_start) {
163-
(TokenExpander::DeclarativeMacro { def_site_token_map, .. }, Some(tt)) => {
164-
(def_site_token_map, *tt)
162+
mbe::Origin::Def => match (&self.macro_def, &self.attr_input_or_mac_def_start) {
163+
(TokenExpander::DeclarativeMacro(expander), Some(tt)) => {
164+
(&expander.def_site_token_map, *tt)
165165
}
166166
_ => panic!("`Origin::Def` used with non-`macro_rules!` macro"),
167167
},
@@ -198,7 +198,7 @@ fn make_hygiene_info(
198198
_ => None,
199199
});
200200

201-
let macro_def = db.macro_def(loc.def).ok()?;
201+
let macro_def = db.macro_def(loc.def);
202202
let (_, exp_map) = db.parse_macro_expansion(macro_file).value;
203203
let macro_arg = db.macro_arg(macro_file.macro_call_id).unwrap_or_else(|| {
204204
Arc::new((

0 commit comments

Comments
 (0)