@@ -4,6 +4,7 @@ use std::mem;
4
4
5
5
use mbe:: { SyntheticToken , SyntheticTokenId , TokenMap } ;
6
6
use rustc_hash:: FxHashMap ;
7
+ use smallvec:: SmallVec ;
7
8
use syntax:: {
8
9
ast:: { self , AstNode , HasLoopBody } ,
9
10
match_ast, SyntaxElement , SyntaxKind , SyntaxNode , TextRange ,
@@ -292,25 +293,34 @@ pub(crate) fn reverse_fixups(
292
293
token_map : & TokenMap ,
293
294
undo_info : & SyntaxFixupUndoInfo ,
294
295
) {
295
- tt. token_trees . retain ( |tt| match tt {
296
- tt:: TokenTree :: Leaf ( leaf) => {
297
- token_map. synthetic_token_id ( leaf. id ( ) ) . is_none ( )
298
- || token_map. synthetic_token_id ( leaf. id ( ) ) != Some ( EMPTY_ID )
299
- }
300
- tt:: TokenTree :: Subtree ( st) => st. delimiter . map_or ( true , |d| {
301
- token_map. synthetic_token_id ( d. id ) . is_none ( )
302
- || token_map. synthetic_token_id ( d. id ) != Some ( EMPTY_ID )
303
- } ) ,
304
- } ) ;
305
- tt. token_trees . iter_mut ( ) . for_each ( |tt| match tt {
306
- tt:: TokenTree :: Subtree ( tt) => reverse_fixups ( tt, token_map, undo_info) ,
307
- tt:: TokenTree :: Leaf ( leaf) => {
308
- if let Some ( id) = token_map. synthetic_token_id ( leaf. id ( ) ) {
309
- let original = & undo_info. original [ id. 0 as usize ] ;
310
- * tt = tt:: TokenTree :: Subtree ( original. clone ( ) ) ;
296
+ let tts = std:: mem:: take ( & mut tt. token_trees ) ;
297
+ tt. token_trees = tts
298
+ . into_iter ( )
299
+ . filter ( |tt| match tt {
300
+ tt:: TokenTree :: Leaf ( leaf) => token_map. synthetic_token_id ( leaf. id ( ) ) != Some ( EMPTY_ID ) ,
301
+ tt:: TokenTree :: Subtree ( st) => {
302
+ st. delimiter . map_or ( true , |d| token_map. synthetic_token_id ( d. id ) != Some ( EMPTY_ID ) )
311
303
}
312
- }
313
- } ) ;
304
+ } )
305
+ . flat_map ( |tt| match tt {
306
+ tt:: TokenTree :: Subtree ( mut tt) => {
307
+ reverse_fixups ( & mut tt, token_map, undo_info) ;
308
+ SmallVec :: from_const ( [ tt. into ( ) ] )
309
+ }
310
+ tt:: TokenTree :: Leaf ( leaf) => {
311
+ if let Some ( id) = token_map. synthetic_token_id ( leaf. id ( ) ) {
312
+ let original = undo_info. original [ id. 0 as usize ] . clone ( ) ;
313
+ if original. delimiter . is_none ( ) {
314
+ original. token_trees . into ( )
315
+ } else {
316
+ SmallVec :: from_const ( [ original. into ( ) ] )
317
+ }
318
+ } else {
319
+ SmallVec :: from_const ( [ leaf. into ( ) ] )
320
+ }
321
+ }
322
+ } )
323
+ . collect ( ) ;
314
324
}
315
325
316
326
#[ cfg( test) ]
@@ -319,6 +329,31 @@ mod tests {
319
329
320
330
use super :: reverse_fixups;
321
331
332
+ // The following three functions are only meant to check partial structural equivalence of
333
+ // `TokenTree`s, see the last assertion in `check()`.
334
+ fn check_leaf_eq ( a : & tt:: Leaf , b : & tt:: Leaf ) -> bool {
335
+ match ( a, b) {
336
+ ( tt:: Leaf :: Literal ( a) , tt:: Leaf :: Literal ( b) ) => a. text == b. text ,
337
+ ( tt:: Leaf :: Punct ( a) , tt:: Leaf :: Punct ( b) ) => a. char == b. char ,
338
+ ( tt:: Leaf :: Ident ( a) , tt:: Leaf :: Ident ( b) ) => a. text == b. text ,
339
+ _ => false ,
340
+ }
341
+ }
342
+
343
+ fn check_subtree_eq ( a : & tt:: Subtree , b : & tt:: Subtree ) -> bool {
344
+ a. delimiter . map ( |it| it. kind ) == b. delimiter . map ( |it| it. kind )
345
+ && a. token_trees . len ( ) == b. token_trees . len ( )
346
+ && a. token_trees . iter ( ) . zip ( & b. token_trees ) . all ( |( a, b) | check_tt_eq ( a, b) )
347
+ }
348
+
349
+ fn check_tt_eq ( a : & tt:: TokenTree , b : & tt:: TokenTree ) -> bool {
350
+ match ( a, b) {
351
+ ( tt:: TokenTree :: Leaf ( a) , tt:: TokenTree :: Leaf ( b) ) => check_leaf_eq ( a, b) ,
352
+ ( tt:: TokenTree :: Subtree ( a) , tt:: TokenTree :: Subtree ( b) ) => check_subtree_eq ( a, b) ,
353
+ _ => false ,
354
+ }
355
+ }
356
+
322
357
#[ track_caller]
323
358
fn check ( ra_fixture : & str , mut expect : Expect ) {
324
359
let parsed = syntax:: SourceFile :: parse ( ra_fixture) ;
@@ -331,27 +366,28 @@ mod tests {
331
366
fixups. append ,
332
367
) ;
333
368
334
- let mut actual = tt. to_string ( ) ;
335
- actual. push ( '\n' ) ;
369
+ let actual = format ! ( "{}\n " , tt) ;
336
370
337
371
expect. indent ( false ) ;
338
372
expect. assert_eq ( & actual) ;
339
373
340
374
// the fixed-up tree should be syntactically valid
341
375
let ( parse, _) = mbe:: token_tree_to_syntax_node ( & tt, :: mbe:: TopEntryPoint :: MacroItems ) ;
342
- assert_eq ! (
343
- parse. errors( ) ,
344
- & [ ] ,
376
+ assert ! (
377
+ parse. errors( ) . is_empty( ) ,
345
378
"parse has syntax errors. parse tree:\n {:#?}" ,
346
379
parse. syntax_node( )
347
380
) ;
348
381
349
382
reverse_fixups ( & mut tt, & tmap, & fixups. undo_info ) ;
350
383
351
384
// the fixed-up + reversed version should be equivalent to the original input
352
- // (but token IDs don't matter)
385
+ // modulo token IDs and `Punct`s' spacing.
353
386
let ( original_as_tt, _) = mbe:: syntax_node_to_token_tree ( & parsed. syntax_node ( ) ) ;
354
- assert_eq ! ( tt. to_string( ) , original_as_tt. to_string( ) ) ;
387
+ assert ! (
388
+ check_subtree_eq( & tt, & original_as_tt) ,
389
+ "different token tree: {tt:?}, {original_as_tt:?}"
390
+ ) ;
355
391
}
356
392
357
393
#[ test]
@@ -468,7 +504,7 @@ fn foo() {
468
504
}
469
505
"# ,
470
506
expect ! [ [ r#"
471
- fn foo () {a .__ra_fixup}
507
+ fn foo () {a . __ra_fixup}
472
508
"# ] ] ,
473
509
)
474
510
}
@@ -482,7 +518,7 @@ fn foo() {
482
518
}
483
519
"# ,
484
520
expect ! [ [ r#"
485
- fn foo () {a .__ra_fixup ;}
521
+ fn foo () {a . __ra_fixup ;}
486
522
"# ] ] ,
487
523
)
488
524
}
@@ -497,7 +533,7 @@ fn foo() {
497
533
}
498
534
"# ,
499
535
expect ! [ [ r#"
500
- fn foo () {a .__ra_fixup ; bar () ;}
536
+ fn foo () {a . __ra_fixup ; bar () ;}
501
537
"# ] ] ,
502
538
)
503
539
}
@@ -525,7 +561,7 @@ fn foo() {
525
561
}
526
562
"# ,
527
563
expect ! [ [ r#"
528
- fn foo () {let x = a .__ra_fixup ;}
564
+ fn foo () {let x = a . __ra_fixup ;}
529
565
"# ] ] ,
530
566
)
531
567
}
@@ -541,7 +577,7 @@ fn foo() {
541
577
}
542
578
"# ,
543
579
expect ! [ [ r#"
544
- fn foo () {a .b ; bar () ;}
580
+ fn foo () {a . b ; bar () ;}
545
581
"# ] ] ,
546
582
)
547
583
}
0 commit comments