3
3
use base_db:: { salsa, CrateId , Edition , SourceDatabase } ;
4
4
use either:: Either ;
5
5
use limit:: Limit ;
6
- use mbe:: syntax_node_to_token_tree;
6
+ use mbe:: { syntax_node_to_token_tree, ValueResult } ;
7
7
use rustc_hash:: FxHashSet ;
8
8
use syntax:: {
9
9
ast:: { self , HasAttrs , HasDocComments } ,
@@ -124,16 +124,21 @@ pub trait ExpandDatabase: SourceDatabase {
124
124
fn macro_arg (
125
125
& self ,
126
126
id : MacroCallId ,
127
- ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ;
127
+ ) -> ValueResult <
128
+ Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ,
129
+ Arc < Box < [ SyntaxError ] > > ,
130
+ > ;
128
131
/// Extracts syntax node, corresponding to a macro call. That's a firewall
129
132
/// query, only typing in the macro call itself changes the returned
130
133
/// subtree.
131
- fn macro_arg_text ( & self , id : MacroCallId ) -> Option < GreenNode > ;
132
- /// Gets the expander for this macro. This compiles declarative macros, and
133
- /// just fetches procedural ones.
134
- // FIXME: Rename this
134
+ fn macro_arg_node (
135
+ & self ,
136
+ id : MacroCallId ,
137
+ ) -> ValueResult < Option < GreenNode > , Arc < Box < [ SyntaxError ] > > > ;
138
+ /// Fetches the expander for this macro.
135
139
#[ salsa:: transparent]
136
- fn macro_def ( & self , id : MacroDefId ) -> TokenExpander ;
140
+ fn macro_expander ( & self , id : MacroDefId ) -> TokenExpander ;
141
+ /// Fetches (and compiles) the expander of this decl macro.
137
142
fn decl_macro_expander (
138
143
& self ,
139
144
def_crate : CrateId ,
@@ -335,14 +340,20 @@ fn parse_macro_expansion_error(
335
340
fn macro_arg (
336
341
db : & dyn ExpandDatabase ,
337
342
id : MacroCallId ,
338
- ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > {
343
+ ) -> ValueResult <
344
+ Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ,
345
+ Arc < Box < [ SyntaxError ] > > ,
346
+ > {
339
347
let loc = db. lookup_intern_macro_call ( id) ;
340
348
341
349
if let Some ( EagerCallInfo { arg, arg_id : _, error : _ } ) = loc. eager . as_deref ( ) {
342
- return Some ( Arc :: new ( ( arg. 0 . clone ( ) , arg. 1 . clone ( ) , Default :: default ( ) ) ) ) ;
350
+ return ValueResult :: ok ( Some ( Arc :: new ( ( arg. 0 . clone ( ) , arg. 1 . clone ( ) , Default :: default ( ) ) ) ) ) ;
343
351
}
344
352
345
- let arg = db. macro_arg_text ( id) ?;
353
+ let ValueResult { value, err } = db. macro_arg_node ( id) ;
354
+ let Some ( arg) = value else {
355
+ return ValueResult { value : None , err } ;
356
+ } ;
346
357
347
358
let node = SyntaxNode :: new_root ( arg) ;
348
359
let censor = censor_for_macro_input ( & loc, & node) ;
@@ -360,7 +371,11 @@ fn macro_arg(
360
371
// proc macros expect their inputs without parentheses, MBEs expect it with them included
361
372
tt. delimiter = tt:: Delimiter :: unspecified ( ) ;
362
373
}
363
- Some ( Arc :: new ( ( tt, tmap, fixups. undo_info ) ) )
374
+ let val = Some ( Arc :: new ( ( tt, tmap, fixups. undo_info ) ) ) ;
375
+ match err {
376
+ Some ( err) => ValueResult :: new ( val, err) ,
377
+ None => ValueResult :: ok ( val) ,
378
+ }
364
379
}
365
380
366
381
/// Certain macro calls expect some nodes in the input to be preprocessed away, namely:
@@ -402,9 +417,43 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
402
417
. unwrap_or_default ( )
403
418
}
404
419
405
- fn macro_arg_text ( db : & dyn ExpandDatabase , id : MacroCallId ) -> Option < GreenNode > {
420
+ fn macro_arg_node (
421
+ db : & dyn ExpandDatabase ,
422
+ id : MacroCallId ,
423
+ ) -> ValueResult < Option < GreenNode > , Arc < Box < [ SyntaxError ] > > > {
424
+ let err = || -> Arc < Box < [ _ ] > > {
425
+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
426
+ "invalid macro call" . to_owned ( ) ,
427
+ syntax:: TextSize :: from ( 0 ) ,
428
+ ) ] ) )
429
+ } ;
406
430
let loc = db. lookup_intern_macro_call ( id) ;
407
- let arg = loc. kind . arg ( db) ?. value ;
431
+ let arg = if let MacroDefKind :: BuiltInEager ( ..) = loc. def . kind {
432
+ let res = if let Some ( EagerCallInfo { arg, .. } ) = loc. eager . as_deref ( ) {
433
+ Some ( mbe:: token_tree_to_syntax_node ( & arg. 0 , mbe:: TopEntryPoint :: Expr ) . 0 )
434
+ } else {
435
+ loc. kind
436
+ . arg ( db)
437
+ . and_then ( |arg| ast:: TokenTree :: cast ( arg. value ) )
438
+ . map ( |tt| tt. reparse_as_expr ( ) . to_syntax ( ) )
439
+ } ;
440
+
441
+ match res {
442
+ Some ( res) if res. errors ( ) . is_empty ( ) => res. syntax_node ( ) ,
443
+ Some ( res) => {
444
+ return ValueResult :: new (
445
+ Some ( res. syntax_node ( ) . green ( ) . into ( ) ) ,
446
+ Arc :: new ( Box :: from ( res. errors ( ) ) ) ,
447
+ )
448
+ }
449
+ None => return ValueResult :: only_err ( err ( ) ) ,
450
+ }
451
+ } else {
452
+ match loc. kind . arg ( db) {
453
+ Some ( res) => res. value ,
454
+ None => return ValueResult :: only_err ( err ( ) ) ,
455
+ }
456
+ } ;
408
457
if matches ! ( loc. kind, MacroCallKind :: FnLike { .. } ) {
409
458
let first = arg. first_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
410
459
let last = arg. last_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
@@ -419,20 +468,13 @@ fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode>
419
468
// Some day, we'll have explicit recursion counters for all
420
469
// recursive things, at which point this code might be removed.
421
470
cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
422
- return None ;
471
+ return ValueResult :: only_err ( Arc :: new ( Box :: new ( [ SyntaxError :: new (
472
+ "unbalanced token tree" . to_owned ( ) ,
473
+ arg. text_range ( ) ,
474
+ ) ] ) ) ) ;
423
475
}
424
476
}
425
- if let Some ( EagerCallInfo { arg, .. } ) = loc. eager . as_deref ( ) {
426
- Some (
427
- mbe:: token_tree_to_syntax_node ( & arg. 0 , mbe:: TopEntryPoint :: Expr )
428
- . 0
429
- . syntax_node ( )
430
- . green ( )
431
- . into ( ) ,
432
- )
433
- } else {
434
- Some ( arg. green ( ) . into ( ) )
435
- }
477
+ ValueResult :: ok ( Some ( arg. green ( ) . into ( ) ) )
436
478
}
437
479
438
480
fn decl_macro_expander (
@@ -474,7 +516,7 @@ fn decl_macro_expander(
474
516
Arc :: new ( DeclarativeMacroExpander { mac, def_site_token_map } )
475
517
}
476
518
477
- fn macro_def ( db : & dyn ExpandDatabase , id : MacroDefId ) -> TokenExpander {
519
+ fn macro_expander ( db : & dyn ExpandDatabase , id : MacroDefId ) -> TokenExpander {
478
520
match id. kind {
479
521
MacroDefKind :: Declarative ( ast_id) => {
480
522
TokenExpander :: DeclarativeMacro ( db. decl_macro_expander ( id. krate , ast_id) )
@@ -491,20 +533,10 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
491
533
let _p = profile:: span ( "macro_expand" ) ;
492
534
let loc = db. lookup_intern_macro_call ( id) ;
493
535
494
- // This might look a bit odd, but we do not expand the inputs to eager macros here.
495
- // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
496
- // That kind of expansion uses the ast id map of an eager macros input though which goes through
497
- // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
498
- // will end up going through here again, whereas we want to just want to inspect the raw input.
499
- // As such we just return the input subtree here.
500
- if let Some ( EagerCallInfo { arg, arg_id : None , error } ) = loc. eager . as_deref ( ) {
501
- return ExpandResult { value : Arc :: new ( arg. 0 . clone ( ) ) , err : error. clone ( ) } ;
502
- }
503
-
504
- let ( ExpandResult { value : mut tt, mut err } , tmap) = match loc. def . kind {
536
+ let ExpandResult { value : tt, mut err } = match loc. def . kind {
505
537
MacroDefKind :: ProcMacro ( ..) => return db. expand_proc_macro ( id) ,
506
538
MacroDefKind :: BuiltInDerive ( expander, ..) => {
507
- let arg = db. macro_arg_text ( id) . unwrap ( ) ;
539
+ let arg = db. macro_arg_node ( id) . value . unwrap ( ) ;
508
540
509
541
let node = SyntaxNode :: new_root ( arg) ;
510
542
let censor = censor_for_macro_input ( & loc, & node) ;
@@ -520,10 +552,13 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
520
552
521
553
// this cast is a bit sus, can we avoid losing the typedness here?
522
554
let adt = ast:: Adt :: cast ( node) . unwrap ( ) ;
523
- ( expander. expand ( db, id, & adt, & tmap) , Some ( ( tmap, fixups. undo_info ) ) )
555
+ let mut res = expander. expand ( db, id, & adt, & tmap) ;
556
+ fixup:: reverse_fixups ( & mut res. value , & tmap, & fixups. undo_info ) ;
557
+ res
524
558
}
525
559
_ => {
526
- let Some ( macro_arg) = db. macro_arg ( id) else {
560
+ let ValueResult { value, err } = db. macro_arg ( id) ;
561
+ let Some ( macro_arg) = value else {
527
562
return ExpandResult {
528
563
value : Arc :: new ( tt:: Subtree {
529
564
delimiter : tt:: Delimiter :: UNSPECIFIED ,
@@ -534,18 +569,43 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
534
569
err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
535
570
} ;
536
571
} ;
572
+
537
573
let ( arg, arg_tm, undo_info) = & * macro_arg;
538
574
let mut res = match loc. def . kind {
539
575
MacroDefKind :: Declarative ( id) => {
540
576
db. decl_macro_expander ( loc. def . krate , id) . expand ( arg. clone ( ) )
541
577
}
542
578
MacroDefKind :: BuiltIn ( it, _) => it. expand ( db, id, & arg) . map_err ( Into :: into) ,
579
+ // This might look a bit odd, but we do not expand the inputs to eager macros here.
580
+ // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
581
+ // That kind of expansion uses the ast id map of an eager macros input though which goes through
582
+ // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
583
+ // will end up going through here again, whereas we want to just want to inspect the raw input.
584
+ // As such we just return the input subtree here.
585
+ MacroDefKind :: BuiltInEager ( ..) if loc. eager . is_none ( ) => {
586
+ let mut arg = arg. clone ( ) ;
587
+ fixup:: reverse_fixups ( & mut arg, arg_tm, undo_info) ;
588
+
589
+ return ExpandResult {
590
+ value : Arc :: new ( arg) ,
591
+ err : err. map ( |err| {
592
+ let mut buf = String :: new ( ) ;
593
+ for err in & * * err {
594
+ use std:: fmt:: Write ;
595
+ _ = write ! ( buf, "{}, " , err) ;
596
+ }
597
+ buf. pop ( ) ;
598
+ buf. pop ( ) ;
599
+ ExpandError :: other ( buf)
600
+ } ) ,
601
+ } ;
602
+ }
543
603
MacroDefKind :: BuiltInEager ( it, _) => it. expand ( db, id, & arg) . map_err ( Into :: into) ,
544
604
MacroDefKind :: BuiltInAttr ( it, _) => it. expand ( db, id, & arg) ,
545
605
_ => unreachable ! ( ) ,
546
606
} ;
547
607
fixup:: reverse_fixups ( & mut res. value , arg_tm, undo_info) ;
548
- ( res, None )
608
+ res
549
609
}
550
610
} ;
551
611
@@ -559,24 +619,23 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
559
619
return value;
560
620
}
561
621
562
- if let Some ( ( arg_tm, undo_info) ) = & tmap {
563
- fixup:: reverse_fixups ( & mut tt, arg_tm, undo_info) ;
564
- }
565
-
566
622
ExpandResult { value : Arc :: new ( tt) , err }
567
623
}
568
624
569
625
fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > {
570
626
let loc = db. lookup_intern_macro_call ( id) ;
571
- let Some ( macro_arg) = db. macro_arg ( id) else {
627
+ let Some ( macro_arg) = db. macro_arg ( id) . value else {
572
628
return ExpandResult {
573
629
value : Arc :: new ( tt:: Subtree {
574
630
delimiter : tt:: Delimiter :: UNSPECIFIED ,
575
631
token_trees : Vec :: new ( ) ,
576
632
} ) ,
633
+ // FIXME: We should make sure to enforce an invariant that invalid macro
634
+ // calls do not reach this call path!
577
635
err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
578
636
} ;
579
637
} ;
638
+
580
639
let ( arg_tt, arg_tm, undo_info) = & * macro_arg;
581
640
582
641
let expander = match loc. def . kind {
0 commit comments