@@ -108,7 +108,7 @@ pub trait ExpandDatabase: SourceDatabase {
108
108
fn macro_arg (
109
109
& self ,
110
110
id : MacroCallId ,
111
- ) -> ValueResult < Option < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) > , Arc < Box < [ SyntaxError ] > > > ;
111
+ ) -> ValueResult < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) , Arc < Box < [ SyntaxError ] > > > ;
112
112
/// Fetches the expander for this macro.
113
113
#[ salsa:: transparent]
114
114
#[ salsa:: invoke( TokenExpander :: macro_expander) ]
@@ -326,58 +326,77 @@ fn macro_arg(
326
326
db : & dyn ExpandDatabase ,
327
327
id : MacroCallId ,
328
328
// FIXME: consider the following by putting fixup info into eager call info args
329
- // ) -> ValueResult<Option<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>>, Arc<Box<[SyntaxError]>>> {
330
- ) -> ValueResult < Option < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) > , Arc < Box < [ SyntaxError ] > > > {
331
- let mismatched_delimiters = |arg : & SyntaxNode | {
332
- let first = arg. first_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
333
- let last = arg. last_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
334
- let well_formed_tt =
335
- matches ! ( ( first, last) , ( T ![ '(' ] , T ![ ')' ] ) | ( T ![ '[' ] , T ![ ']' ] ) | ( T ![ '{' ] , T ![ '}' ] ) ) ;
336
- if !well_formed_tt {
337
- // Don't expand malformed (unbalanced) macro invocations. This is
338
- // less than ideal, but trying to expand unbalanced macro calls
339
- // sometimes produces pathological, deeply nested code which breaks
340
- // all kinds of things.
341
- //
342
- // Some day, we'll have explicit recursion counters for all
343
- // recursive things, at which point this code might be removed.
344
- cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
345
- Some ( Arc :: new ( Box :: new ( [ SyntaxError :: new (
346
- "unbalanced token tree" . to_owned ( ) ,
347
- arg. text_range ( ) ,
348
- ) ] ) as Box < [ _ ] > ) )
349
- } else {
350
- None
351
- }
352
- } ;
329
+ // ) -> ValueResult<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
330
+ ) -> ValueResult < ( Arc < tt:: Subtree > , SyntaxFixupUndoInfo ) , Arc < Box < [ SyntaxError ] > > > {
353
331
let loc = db. lookup_intern_macro_call ( id) ;
354
332
if let Some ( EagerCallInfo { arg, .. } ) = matches ! ( loc. def. kind, MacroDefKind :: BuiltInEager ( ..) )
355
333
. then ( || loc. eager . as_deref ( ) )
356
334
. flatten ( )
357
335
{
358
- ValueResult :: ok ( Some ( ( arg. clone ( ) , SyntaxFixupUndoInfo :: NONE ) ) )
336
+ ValueResult :: ok ( ( arg. clone ( ) , SyntaxFixupUndoInfo :: NONE ) )
359
337
} else {
360
338
let ( parse, map) = parse_with_map ( db, loc. kind . file_id ( ) ) ;
361
339
let root = parse. syntax_node ( ) ;
362
340
363
341
let syntax = match loc. kind {
364
342
MacroCallKind :: FnLike { ast_id, .. } => {
343
+ let dummy_tt = |kind| {
344
+ (
345
+ Arc :: new ( tt:: Subtree {
346
+ delimiter : tt:: Delimiter {
347
+ open : loc. call_site ,
348
+ close : loc. call_site ,
349
+ kind,
350
+ } ,
351
+ token_trees : Box :: default ( ) ,
352
+ } ) ,
353
+ SyntaxFixupUndoInfo :: default ( ) ,
354
+ )
355
+ } ;
356
+
365
357
let node = & ast_id. to_ptr ( db) . to_node ( & root) ;
366
358
let offset = node. syntax ( ) . text_range ( ) . start ( ) ;
367
- match node. token_tree ( ) {
368
- Some ( tt) => {
369
- let tt = tt. syntax ( ) ;
370
- if let Some ( e) = mismatched_delimiters ( tt) {
371
- return ValueResult :: only_err ( e) ;
372
- }
373
- tt. clone ( )
374
- }
375
- None => {
376
- return ValueResult :: only_err ( Arc :: new ( Box :: new ( [
377
- SyntaxError :: new_at_offset ( "missing token tree" . to_owned ( ) , offset) ,
378
- ] ) ) ) ;
379
- }
359
+ let Some ( tt) = node. token_tree ( ) else {
360
+ return ValueResult :: new (
361
+ dummy_tt ( tt:: DelimiterKind :: Invisible ) ,
362
+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
363
+ "missing token tree" . to_owned ( ) ,
364
+ offset,
365
+ ) ] ) ) ,
366
+ ) ;
367
+ } ;
368
+ let first = tt. left_delimiter_token ( ) . map ( |it| it. kind ( ) ) . unwrap_or ( T ! [ '(' ] ) ;
369
+ let last = tt. right_delimiter_token ( ) . map ( |it| it. kind ( ) ) . unwrap_or ( T ! [ . ] ) ;
370
+
371
+ let mismatched_delimiters = !matches ! (
372
+ ( first, last) ,
373
+ ( T ![ '(' ] , T ![ ')' ] ) | ( T ![ '[' ] , T ![ ']' ] ) | ( T ![ '{' ] , T ![ '}' ] )
374
+ ) ;
375
+ if mismatched_delimiters {
376
+ // Don't expand malformed (unbalanced) macro invocations. This is
377
+ // less than ideal, but trying to expand unbalanced macro calls
378
+ // sometimes produces pathological, deeply nested code which breaks
379
+ // all kinds of things.
380
+ //
381
+ // So instead, we'll return an empty subtree here
382
+ cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
383
+
384
+ let kind = match first {
385
+ _ if loc. def . is_proc_macro ( ) => tt:: DelimiterKind :: Invisible ,
386
+ T ! [ '(' ] => tt:: DelimiterKind :: Parenthesis ,
387
+ T ! [ '[' ] => tt:: DelimiterKind :: Bracket ,
388
+ T ! [ '{' ] => tt:: DelimiterKind :: Brace ,
389
+ _ => tt:: DelimiterKind :: Invisible ,
390
+ } ;
391
+ return ValueResult :: new (
392
+ dummy_tt ( kind) ,
393
+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
394
+ "mismatched delimiters" . to_owned ( ) ,
395
+ offset,
396
+ ) ] ) ) ,
397
+ ) ;
380
398
}
399
+ tt. syntax ( ) . clone ( )
381
400
}
382
401
MacroCallKind :: Derive { ast_id, .. } => {
383
402
ast_id. to_ptr ( db) . to_node ( & root) . syntax ( ) . clone ( )
@@ -427,15 +446,15 @@ fn macro_arg(
427
446
428
447
if matches ! ( loc. def. kind, MacroDefKind :: BuiltInEager ( ..) ) {
429
448
match parse. errors ( ) {
430
- [ ] => ValueResult :: ok ( Some ( ( Arc :: new ( tt) , undo_info) ) ) ,
449
+ [ ] => ValueResult :: ok ( ( Arc :: new ( tt) , undo_info) ) ,
431
450
errors => ValueResult :: new (
432
- Some ( ( Arc :: new ( tt) , undo_info) ) ,
451
+ ( Arc :: new ( tt) , undo_info) ,
433
452
// Box::<[_]>::from(res.errors()), not stable yet
434
453
Arc :: new ( errors. to_vec ( ) . into_boxed_slice ( ) ) ,
435
454
) ,
436
455
}
437
456
} else {
438
- ValueResult :: ok ( Some ( ( Arc :: new ( tt) , undo_info) ) )
457
+ ValueResult :: ok ( ( Arc :: new ( tt) , undo_info) )
439
458
}
440
459
}
441
460
}
@@ -519,21 +538,20 @@ fn macro_expand(
519
538
expander. expand ( db, macro_call_id, & node, map. as_ref ( ) )
520
539
}
521
540
_ => {
522
- let ValueResult { value, err } = db. macro_arg ( macro_call_id) ;
523
- let Some ( ( macro_arg, undo_info) ) = value else {
524
- return ExpandResult {
525
- value : CowArc :: Owned ( tt:: Subtree {
526
- delimiter : tt:: Delimiter :: invisible_spanned ( loc. call_site ) ,
527
- token_trees : Box :: new ( [ ] ) ,
528
- } ) ,
529
- // FIXME: We should make sure to enforce an invariant that invalid macro
530
- // calls do not reach this call path!
531
- err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
532
- } ;
541
+ let ValueResult { value : ( macro_arg, undo_info) , err } = db. macro_arg ( macro_call_id) ;
542
+ let format_parse_err = |err : Arc < Box < [ SyntaxError ] > > | {
543
+ let mut buf = String :: new ( ) ;
544
+ for err in & * * err {
545
+ use std:: fmt:: Write ;
546
+ _ = write ! ( buf, "{}, " , err) ;
547
+ }
548
+ buf. pop ( ) ;
549
+ buf. pop ( ) ;
550
+ ExpandError :: other ( buf)
533
551
} ;
534
552
535
553
let arg = & * macro_arg;
536
- match loc. def . kind {
554
+ let res = match loc. def . kind {
537
555
MacroDefKind :: Declarative ( id) => {
538
556
db. decl_macro_expander ( loc. def . krate , id) . expand ( db, arg. clone ( ) , macro_call_id)
539
557
}
@@ -549,16 +567,7 @@ fn macro_expand(
549
567
MacroDefKind :: BuiltInEager ( ..) if loc. eager . is_none ( ) => {
550
568
return ExpandResult {
551
569
value : CowArc :: Arc ( macro_arg. clone ( ) ) ,
552
- err : err. map ( |err| {
553
- let mut buf = String :: new ( ) ;
554
- for err in & * * err {
555
- use std:: fmt:: Write ;
556
- _ = write ! ( buf, "{}, " , err) ;
557
- }
558
- buf. pop ( ) ;
559
- buf. pop ( ) ;
560
- ExpandError :: other ( buf)
561
- } ) ,
570
+ err : err. map ( format_parse_err) ,
562
571
} ;
563
572
}
564
573
MacroDefKind :: BuiltInEager ( it, _) => {
@@ -570,6 +579,11 @@ fn macro_expand(
570
579
res
571
580
}
572
581
_ => unreachable ! ( ) ,
582
+ } ;
583
+ ExpandResult {
584
+ value : res. value ,
585
+ // if the arg had parse errors, show them instead of the expansion errors
586
+ err : err. map ( format_parse_err) . or ( res. err ) ,
573
587
}
574
588
}
575
589
} ;
@@ -597,17 +611,7 @@ fn macro_expand(
597
611
598
612
fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > {
599
613
let loc = db. lookup_intern_macro_call ( id) ;
600
- let Some ( ( macro_arg, undo_info) ) = db. macro_arg ( id) . value else {
601
- return ExpandResult {
602
- value : Arc :: new ( tt:: Subtree {
603
- delimiter : tt:: Delimiter :: invisible_spanned ( loc. call_site ) ,
604
- token_trees : Box :: new ( [ ] ) ,
605
- } ) ,
606
- // FIXME: We should make sure to enforce an invariant that invalid macro
607
- // calls do not reach this call path!
608
- err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
609
- } ;
610
- } ;
614
+ let ( macro_arg, undo_info) = db. macro_arg ( id) . value ;
611
615
612
616
let expander = match loc. def . kind {
613
617
MacroDefKind :: ProcMacro ( expander, ..) => expander,
0 commit comments