Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4ff9339

Browse files
committed
Skip buildin subtrees for builtin derives
1 parent ff15634 commit 4ff9339

File tree

4 files changed

+244
-77
lines changed

4 files changed

+244
-77
lines changed

crates/hir-expand/src/builtin_derive_macro.rs

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ use crate::{
1212
name::{AsName, Name},
1313
tt::{self, TokenId},
1414
};
15-
use syntax::ast::{
16-
self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds,
17-
};
15+
use syntax::ast::{self, AstNode, FieldList, HasAttrs, HasGenericParams, HasName, HasTypeBounds};
1816

1917
use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
2018

@@ -30,12 +28,13 @@ macro_rules! register_builtin {
3028
&self,
3129
db: &dyn ExpandDatabase,
3230
id: MacroCallId,
33-
tt: &tt::Subtree,
31+
tt: &ast::Adt,
32+
token_map: &TokenMap,
3433
) -> ExpandResult<tt::Subtree> {
3534
let expander = match *self {
3635
$( BuiltinDeriveExpander::$trait => $expand, )*
3736
};
38-
expander(db, id, tt)
37+
expander(db, id, tt, token_map)
3938
}
4039

4140
fn find_by_name(name: &name::Name) -> Option<Self> {
@@ -118,13 +117,13 @@ impl VariantShape {
118117
}
119118
}
120119

121-
fn from(value: Option<FieldList>, token_map: &TokenMap) -> Result<Self, ExpandError> {
120+
fn from(tm: &TokenMap, value: Option<FieldList>) -> Result<Self, ExpandError> {
122121
let r = match value {
123122
None => VariantShape::Unit,
124123
Some(FieldList::RecordFieldList(it)) => VariantShape::Struct(
125124
it.fields()
126125
.map(|it| it.name())
127-
.map(|it| name_to_token(token_map, it))
126+
.map(|it| name_to_token(tm, it))
128127
.collect::<Result<_, _>>()?,
129128
),
130129
Some(FieldList::TupleFieldList(it)) => VariantShape::Tuple(it.fields().count()),
@@ -190,25 +189,12 @@ struct BasicAdtInfo {
190189
associated_types: Vec<tt::Subtree>,
191190
}
192191

193-
fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
194-
let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems);
195-
let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
196-
debug!("derive node didn't parse");
197-
ExpandError::other("invalid item definition")
198-
})?;
199-
let item = macro_items.items().next().ok_or_else(|| {
200-
debug!("no module item parsed");
201-
ExpandError::other("no item found")
202-
})?;
203-
let adt = ast::Adt::cast(item.syntax().clone()).ok_or_else(|| {
204-
debug!("expected adt, found: {:?}", item);
205-
ExpandError::other("expected struct, enum or union")
206-
})?;
192+
fn parse_adt(tm: &TokenMap, adt: &ast::Adt) -> Result<BasicAdtInfo, ExpandError> {
207193
let (name, generic_param_list, shape) = match &adt {
208194
ast::Adt::Struct(it) => (
209195
it.name(),
210196
it.generic_param_list(),
211-
AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?),
197+
AdtShape::Struct(VariantShape::from(tm, it.field_list())?),
212198
),
213199
ast::Adt::Enum(it) => {
214200
let default_variant = it
@@ -227,8 +213,8 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
227213
.flat_map(|it| it.variants())
228214
.map(|it| {
229215
Ok((
230-
name_to_token(&token_map, it.name())?,
231-
VariantShape::from(it.field_list(), &token_map)?,
216+
name_to_token(tm, it.name())?,
217+
VariantShape::from(tm, it.field_list())?,
232218
))
233219
})
234220
.collect::<Result<_, ExpandError>>()?,
@@ -298,7 +284,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
298284
})
299285
.map(|it| mbe::syntax_node_to_token_tree(it.syntax()).0)
300286
.collect();
301-
let name_token = name_to_token(&token_map, name)?;
287+
let name_token = name_to_token(&tm, name)?;
302288
Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types })
303289
}
304290

@@ -345,11 +331,12 @@ fn name_to_token(token_map: &TokenMap, name: Option<ast::Name>) -> Result<tt::Id
345331
/// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and
346332
/// therefore does not get bound by the derived trait.
347333
fn expand_simple_derive(
348-
tt: &tt::Subtree,
334+
tt: &ast::Adt,
335+
tm: &TokenMap,
349336
trait_path: tt::Subtree,
350337
make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::Subtree,
351338
) -> ExpandResult<tt::Subtree> {
352-
let info = match parse_adt(tt) {
339+
let info = match parse_adt(tm, tt) {
353340
Ok(info) => info,
354341
Err(e) => return ExpandResult::new(tt::Subtree::empty(), e),
355342
};
@@ -405,19 +392,21 @@ fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree
405392
fn copy_expand(
406393
db: &dyn ExpandDatabase,
407394
id: MacroCallId,
408-
tt: &tt::Subtree,
395+
tt: &ast::Adt,
396+
tm: &TokenMap,
409397
) -> ExpandResult<tt::Subtree> {
410398
let krate = find_builtin_crate(db, id);
411-
expand_simple_derive(tt, quote! { #krate::marker::Copy }, |_| quote! {})
399+
expand_simple_derive(tt, tm, quote! { #krate::marker::Copy }, |_| quote! {})
412400
}
413401

414402
fn clone_expand(
415403
db: &dyn ExpandDatabase,
416404
id: MacroCallId,
417-
tt: &tt::Subtree,
405+
tt: &ast::Adt,
406+
tm: &TokenMap,
418407
) -> ExpandResult<tt::Subtree> {
419408
let krate = find_builtin_crate(db, id);
420-
expand_simple_derive(tt, quote! { #krate::clone::Clone }, |adt| {
409+
expand_simple_derive(tt, tm, quote! { #krate::clone::Clone }, |adt| {
421410
if matches!(adt.shape, AdtShape::Union) {
422411
let star = tt::Punct {
423412
char: '*',
@@ -479,10 +468,11 @@ fn and_and() -> ::tt::Subtree<TokenId> {
479468
fn default_expand(
480469
db: &dyn ExpandDatabase,
481470
id: MacroCallId,
482-
tt: &tt::Subtree,
471+
tt: &ast::Adt,
472+
tm: &TokenMap,
483473
) -> ExpandResult<tt::Subtree> {
484474
let krate = &find_builtin_crate(db, id);
485-
expand_simple_derive(tt, quote! { #krate::default::Default }, |adt| {
475+
expand_simple_derive(tt, tm, quote! { #krate::default::Default }, |adt| {
486476
let body = match &adt.shape {
487477
AdtShape::Struct(fields) => {
488478
let name = &adt.name;
@@ -518,10 +508,11 @@ fn default_expand(
518508
fn debug_expand(
519509
db: &dyn ExpandDatabase,
520510
id: MacroCallId,
521-
tt: &tt::Subtree,
511+
tt: &ast::Adt,
512+
tm: &TokenMap,
522513
) -> ExpandResult<tt::Subtree> {
523514
let krate = &find_builtin_crate(db, id);
524-
expand_simple_derive(tt, quote! { #krate::fmt::Debug }, |adt| {
515+
expand_simple_derive(tt, tm, quote! { #krate::fmt::Debug }, |adt| {
525516
let for_variant = |name: String, v: &VariantShape| match v {
526517
VariantShape::Struct(fields) => {
527518
let for_fields = fields.iter().map(|it| {
@@ -598,10 +589,11 @@ fn debug_expand(
598589
fn hash_expand(
599590
db: &dyn ExpandDatabase,
600591
id: MacroCallId,
601-
tt: &tt::Subtree,
592+
tt: &ast::Adt,
593+
tm: &TokenMap,
602594
) -> ExpandResult<tt::Subtree> {
603595
let krate = &find_builtin_crate(db, id);
604-
expand_simple_derive(tt, quote! { #krate::hash::Hash }, |adt| {
596+
expand_simple_derive(tt, tm, quote! { #krate::hash::Hash }, |adt| {
605597
if matches!(adt.shape, AdtShape::Union) {
606598
// FIXME: Return expand error here
607599
return quote! {};
@@ -646,19 +638,21 @@ fn hash_expand(
646638
fn eq_expand(
647639
db: &dyn ExpandDatabase,
648640
id: MacroCallId,
649-
tt: &tt::Subtree,
641+
tt: &ast::Adt,
642+
tm: &TokenMap,
650643
) -> ExpandResult<tt::Subtree> {
651644
let krate = find_builtin_crate(db, id);
652-
expand_simple_derive(tt, quote! { #krate::cmp::Eq }, |_| quote! {})
645+
expand_simple_derive(tt, tm, quote! { #krate::cmp::Eq }, |_| quote! {})
653646
}
654647

655648
fn partial_eq_expand(
656649
db: &dyn ExpandDatabase,
657650
id: MacroCallId,
658-
tt: &tt::Subtree,
651+
tt: &ast::Adt,
652+
tm: &TokenMap,
659653
) -> ExpandResult<tt::Subtree> {
660654
let krate = find_builtin_crate(db, id);
661-
expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }, |adt| {
655+
expand_simple_derive(tt, tm, quote! { #krate::cmp::PartialEq }, |adt| {
662656
if matches!(adt.shape, AdtShape::Union) {
663657
// FIXME: Return expand error here
664658
return quote! {};
@@ -722,10 +716,11 @@ fn self_and_other_patterns(
722716
fn ord_expand(
723717
db: &dyn ExpandDatabase,
724718
id: MacroCallId,
725-
tt: &tt::Subtree,
719+
tt: &ast::Adt,
720+
tm: &TokenMap,
726721
) -> ExpandResult<tt::Subtree> {
727722
let krate = &find_builtin_crate(db, id);
728-
expand_simple_derive(tt, quote! { #krate::cmp::Ord }, |adt| {
723+
expand_simple_derive(tt, tm, quote! { #krate::cmp::Ord }, |adt| {
729724
fn compare(
730725
krate: &tt::TokenTree,
731726
left: tt::Subtree,
@@ -786,10 +781,11 @@ fn ord_expand(
786781
fn partial_ord_expand(
787782
db: &dyn ExpandDatabase,
788783
id: MacroCallId,
789-
tt: &tt::Subtree,
784+
tt: &ast::Adt,
785+
tm: &TokenMap,
790786
) -> ExpandResult<tt::Subtree> {
791787
let krate = &find_builtin_crate(db, id);
792-
expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }, |adt| {
788+
expand_simple_derive(tt, tm, quote! { #krate::cmp::PartialOrd }, |adt| {
793789
fn compare(
794790
krate: &tt::TokenTree,
795791
left: tt::Subtree,

crates/hir-expand/src/db.rs

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ impl TokenExpander {
5555
TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into),
5656
TokenExpander::BuiltinEager(it) => it.expand(db, id, tt).map_err(Into::into),
5757
TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt),
58-
TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
58+
TokenExpander::BuiltinDerive(_) => {
59+
unreachable!("builtin derives should be expanded manually")
60+
}
5961
TokenExpander::ProcMacro(_) => {
6062
unreachable!("ExpandDatabase::expand_proc_macro should be used for proc macros")
6163
}
@@ -232,6 +234,11 @@ pub fn expand_speculative(
232234
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
233235
pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
234236
}
237+
MacroDefKind::BuiltInDerive(expander, ..) => {
238+
// this cast is a bit sus, can we avoid losing the typedness here?
239+
let adt = ast::Adt::cast(speculative_args.clone()).unwrap();
240+
expander.expand(db, actual_macro_call, &adt, &spec_args_tmap)
241+
}
235242
_ => macro_def.expand(db, actual_macro_call, &tt),
236243
};
237244

@@ -333,6 +340,9 @@ fn macro_arg(
333340
Some(Arc::new((tt, tmap, fixups.undo_info)))
334341
}
335342

343+
/// Certain macro calls expect some nodes in the input to be preprocessed away, namely:
344+
/// - derives expect all `#[derive(..)]` invocations up to the currently invoked one to be stripped
345+
/// - attributes expect the invoking attribute to be stripped
336346
fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<SyntaxNode> {
337347
// FIXME: handle `cfg_attr`
338348
(|| {
@@ -451,37 +461,59 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
451461
return ExpandResult { value: Arc::new(arg.0.clone()), err: error.clone() };
452462
}
453463

454-
if let MacroDefKind::ProcMacro(..) = loc.def.kind {
455-
return db.expand_proc_macro(id);
456-
}
457-
458-
let expander = match db.macro_def(loc.def) {
459-
Ok(it) => it,
460-
// FIXME: We should make sure to enforce a variant that invalid macro
461-
// definitions do not get expanders that could reach this call path!
462-
Err(err) => {
463-
return ExpandResult {
464-
value: Arc::new(tt::Subtree {
465-
delimiter: tt::Delimiter::UNSPECIFIED,
466-
token_trees: vec![],
467-
}),
468-
err: Some(ExpandError::other(format!("invalid macro definition: {err}"))),
469-
}
464+
let (ExpandResult { value: mut tt, mut err }, tmap) = match loc.def.kind {
465+
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(id),
466+
MacroDefKind::BuiltInDerive(expander, ..) => {
467+
let arg = db.macro_arg_text(id).unwrap();
468+
469+
let node = SyntaxNode::new_root(arg);
470+
let censor = censor_for_macro_input(&loc, &node);
471+
let mut fixups = fixup::fixup_syntax(&node);
472+
fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new())));
473+
let (tmap, _) = mbe::syntax_node_to_token_map_with_modifications(
474+
&node,
475+
fixups.token_map,
476+
fixups.next_id,
477+
fixups.replace,
478+
fixups.append,
479+
);
480+
481+
// this cast is a bit sus, can we avoid losing the typedness here?
482+
let adt = ast::Adt::cast(node).unwrap();
483+
(expander.expand(db, id, &adt, &tmap), Some((tmap, fixups.undo_info)))
484+
}
485+
_ => {
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+
};
500+
let Some(macro_arg) = db.macro_arg(id) else {
501+
return ExpandResult {
502+
value: Arc::new(tt::Subtree {
503+
delimiter: tt::Delimiter::UNSPECIFIED,
504+
token_trees: Vec::new(),
505+
}),
506+
// FIXME: We should make sure to enforce an invariant that invalid macro
507+
// calls do not reach this call path!
508+
err: Some(ExpandError::other("invalid token tree")),
509+
};
510+
};
511+
let (arg, arg_tm, undo_info) = &*macro_arg;
512+
let mut res = expander.expand(db, id, arg);
513+
fixup::reverse_fixups(&mut res.value, arg_tm, undo_info);
514+
(res, None)
470515
}
471516
};
472-
let Some(macro_arg) = db.macro_arg(id) else {
473-
return ExpandResult {
474-
value: Arc::new(tt::Subtree {
475-
delimiter: tt::Delimiter::UNSPECIFIED,
476-
token_trees: Vec::new(),
477-
}),
478-
// FIXME: We should make sure to enforce an invariant that invalid macro
479-
// calls do not reach this call path!
480-
err: Some(ExpandError::other("invalid token tree")),
481-
};
482-
};
483-
let (arg_tt, arg_tm, undo_info) = &*macro_arg;
484-
let ExpandResult { value: mut tt, mut err } = expander.expand(db, id, arg_tt);
485517

486518
if let Some(EagerCallInfo { error, .. }) = loc.eager.as_deref() {
487519
// FIXME: We should report both errors!
@@ -493,7 +525,9 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
493525
return value;
494526
}
495527

496-
fixup::reverse_fixups(&mut tt, arg_tm, undo_info);
528+
if let Some((arg_tm, undo_info)) = &tmap {
529+
fixup::reverse_fixups(&mut tt, arg_tm, undo_info);
530+
}
497531

498532
ExpandResult { value: Arc::new(tt), err }
499533
}

crates/mbe/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ pub use ::parser::TopEntryPoint;
3434

3535
pub use crate::{
3636
syntax_bridge::{
37-
parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree,
37+
parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_map,
38+
syntax_node_to_token_map_with_modifications, syntax_node_to_token_tree,
3839
syntax_node_to_token_tree_with_modifications, token_tree_to_syntax_node, SyntheticToken,
3940
SyntheticTokenId,
4041
},

0 commit comments

Comments
 (0)