@@ -548,62 +548,83 @@ impl ExprCollector<'_> {
548
548
}
549
549
}
550
550
ast:: Expr :: MacroCall ( e) => {
551
- if let Some ( name) = e. is_macro_rules ( ) . map ( |it| it. as_name ( ) ) {
552
- let mac = MacroDefId {
553
- krate : Some ( self . expander . module . krate ) ,
554
- ast_id : Some ( self . expander . ast_id ( & e) ) ,
555
- kind : MacroDefKind :: Declarative ,
556
- local_inner : false ,
557
- } ;
558
- self . body . item_scope . define_legacy_macro ( name, mac) ;
559
-
560
- // FIXME: do we still need to allocate this as missing ?
561
- self . alloc_expr ( Expr :: Missing , syntax_ptr)
562
- } else {
563
- // File containing the macro call. Expansion errors will be attached here.
564
- let outer_file = self . expander . current_file_id ;
565
-
566
- let macro_call = self . expander . to_source ( AstPtr :: new ( & e) ) ;
567
- let res = self . expander . enter_expand ( self . db , Some ( & self . body . item_scope ) , e) ;
568
-
569
- match res. err {
570
- Some ( ExpandError :: UnresolvedProcMacro ) => {
571
- self . source_map . diagnostics . push ( BodyDiagnostic :: UnresolvedProcMacro (
572
- UnresolvedProcMacro {
573
- file : outer_file,
574
- node : syntax_ptr. clone ( ) . into ( ) ,
575
- precise_location : None ,
576
- macro_name : None ,
577
- } ,
578
- ) ) ;
579
- }
580
- Some ( err) => {
581
- self . source_map . diagnostics . push ( BodyDiagnostic :: MacroError (
582
- MacroError {
583
- file : outer_file,
584
- node : syntax_ptr. clone ( ) . into ( ) ,
585
- message : err. to_string ( ) ,
586
- } ,
587
- ) ) ;
588
- }
589
- None => { }
590
- }
551
+ let mut ids = vec ! [ ] ;
552
+ self . collect_macro_call ( e, syntax_ptr. clone ( ) , |this, expansion| {
553
+ ids. push ( match expansion {
554
+ Some ( it) => this. collect_expr ( it) ,
555
+ None => this. alloc_expr ( Expr :: Missing , syntax_ptr. clone ( ) ) ,
556
+ } )
557
+ } ) ;
558
+ ids[ 0 ]
559
+ }
560
+ }
561
+ }
591
562
592
- match res. value {
593
- Some ( ( mark, expansion) ) => {
594
- self . source_map
595
- . expansions
596
- . insert ( macro_call, self . expander . current_file_id ) ;
597
-
598
- let item_tree = self . db . item_tree ( self . expander . current_file_id ) ;
599
- self . item_trees . insert ( self . expander . current_file_id , item_tree) ;
600
- let id = self . collect_expr ( expansion) ;
601
- self . expander . exit ( self . db , mark) ;
602
- id
603
- }
604
- None => self . alloc_expr ( Expr :: Missing , syntax_ptr) ,
563
+ fn collect_macro_call < F : FnMut ( & mut Self , Option < T > ) , T : ast:: AstNode > (
564
+ & mut self ,
565
+ e : ast:: MacroCall ,
566
+ syntax_ptr : AstPtr < ast:: Expr > ,
567
+ mut collector : F ,
568
+ ) {
569
+ if let Some ( name) = e. is_macro_rules ( ) . map ( |it| it. as_name ( ) ) {
570
+ let mac = MacroDefId {
571
+ krate : Some ( self . expander . module . krate ) ,
572
+ ast_id : Some ( self . expander . ast_id ( & e) ) ,
573
+ kind : MacroDefKind :: Declarative ,
574
+ local_inner : false ,
575
+ } ;
576
+ self . body . item_scope . define_legacy_macro ( name, mac) ;
577
+
578
+ // FIXME: do we still need to allocate this as missing ?
579
+ collector ( self , None ) ;
580
+ } else {
581
+ // File containing the macro call. Expansion errors will be attached here.
582
+ let outer_file = self . expander . current_file_id ;
583
+
584
+ let macro_call = self . expander . to_source ( AstPtr :: new ( & e) ) ;
585
+ let res = self . expander . enter_expand ( self . db , Some ( & self . body . item_scope ) , e) ;
586
+
587
+ match & res. err {
588
+ Some ( ExpandError :: UnresolvedProcMacro ) => {
589
+ self . source_map . diagnostics . push ( BodyDiagnostic :: UnresolvedProcMacro (
590
+ UnresolvedProcMacro {
591
+ file : outer_file,
592
+ node : syntax_ptr. into ( ) ,
593
+ precise_location : None ,
594
+ macro_name : None ,
595
+ } ,
596
+ ) ) ;
597
+ }
598
+ Some ( err) => {
599
+ self . source_map . diagnostics . push ( BodyDiagnostic :: MacroError ( MacroError {
600
+ file : outer_file,
601
+ node : syntax_ptr. into ( ) ,
602
+ message : err. to_string ( ) ,
603
+ } ) ) ;
604
+ }
605
+ None => { }
606
+ }
607
+
608
+ match res. value {
609
+ Some ( ( mark, expansion) ) => {
610
+ // FIXME: Statements are too complicated to recover from error for now.
611
+ // It is because we don't have any hygenine for local variable expansion right now.
612
+ if T :: can_cast ( syntax:: SyntaxKind :: MACRO_STMTS ) && res. err . is_some ( ) {
613
+ self . expander . exit ( self . db , mark) ;
614
+ collector ( self , None ) ;
615
+ } else {
616
+ self . source_map
617
+ . expansions
618
+ . insert ( macro_call, self . expander . current_file_id ) ;
619
+
620
+ let item_tree = self . db . item_tree ( self . expander . current_file_id ) ;
621
+ self . item_trees . insert ( self . expander . current_file_id , item_tree) ;
622
+
623
+ collector ( self , Some ( expansion) ) ;
624
+ self . expander . exit ( self . db , mark) ;
605
625
}
606
626
}
627
+ None => collector ( self , None ) ,
607
628
}
608
629
}
609
630
}
@@ -642,44 +663,75 @@ impl ExprCollector<'_> {
642
663
}
643
664
}
644
665
645
- fn collect_block ( & mut self , block : ast:: BlockExpr ) -> ExprId {
646
- let syntax_node_ptr = AstPtr :: new ( & block. clone ( ) . into ( ) ) ;
647
- self . collect_block_items ( & block) ;
648
- let statements = block
649
- . statements ( )
650
- . filter_map ( |s| {
651
- let stmt = match s {
652
- ast:: Stmt :: LetStmt ( stmt) => {
653
- self . check_cfg ( & stmt) ?;
654
-
655
- let pat = self . collect_pat_opt ( stmt. pat ( ) ) ;
656
- let type_ref = stmt. ty ( ) . map ( |it| TypeRef :: from_ast ( & self . ctx ( ) , it) ) ;
657
- let initializer = stmt. initializer ( ) . map ( |e| self . collect_expr ( e) ) ;
658
- Statement :: Let { pat, type_ref, initializer }
659
- }
660
- ast:: Stmt :: ExprStmt ( stmt) => {
661
- self . check_cfg ( & stmt) ?;
666
+ fn collect_stmt ( & mut self , s : ast:: Stmt ) -> Option < Vec < Statement > > {
667
+ let stmt =
668
+ match s {
669
+ ast:: Stmt :: LetStmt ( stmt) => {
670
+ self . check_cfg ( & stmt) ?;
662
671
663
- Statement :: Expr ( self . collect_expr_opt ( stmt. expr ( ) ) )
664
- }
665
- ast:: Stmt :: Item ( item) => {
666
- self . check_cfg ( & item) ?;
672
+ let pat = self . collect_pat_opt ( stmt. pat ( ) ) ;
673
+ let type_ref = stmt. ty ( ) . map ( |it| TypeRef :: from_ast ( & self . ctx ( ) , it) ) ;
674
+ let initializer = stmt. initializer ( ) . map ( |e| self . collect_expr ( e) ) ;
675
+ vec ! [ Statement :: Let { pat, type_ref, initializer } ]
676
+ }
677
+ ast:: Stmt :: ExprStmt ( stmt) => {
678
+ self . check_cfg ( & stmt) ?;
679
+
680
+ // Note that macro could be expended to multiple statements
681
+ if let Some ( ast:: Expr :: MacroCall ( m) ) = stmt. expr ( ) {
682
+ let syntax_ptr = AstPtr :: new ( & stmt. expr ( ) . unwrap ( ) ) ;
683
+ let mut stmts = vec ! [ ] ;
684
+
685
+ self . collect_macro_call ( m, syntax_ptr. clone ( ) , |this, expansion| {
686
+ match expansion {
687
+ Some ( expansion) => {
688
+ let statements: ast:: MacroStmts = expansion;
689
+ this. collect_stmts_items ( statements. statements ( ) ) ;
667
690
668
- return None ;
691
+ statements. statements ( ) . for_each ( |stmt| {
692
+ if let Some ( mut r) = this. collect_stmt ( stmt) {
693
+ stmts. append ( & mut r) ;
694
+ }
695
+ } ) ;
696
+ if let Some ( expr) = statements. expr ( ) {
697
+ stmts. push ( Statement :: Expr ( this. collect_expr ( expr) ) ) ;
698
+ }
699
+ }
700
+ None => {
701
+ stmts. push ( Statement :: Expr (
702
+ this. alloc_expr ( Expr :: Missing , syntax_ptr. clone ( ) ) ,
703
+ ) ) ;
704
+ }
705
+ }
706
+ } ) ;
707
+ stmts
708
+ } else {
709
+ vec ! [ Statement :: Expr ( self . collect_expr_opt( stmt. expr( ) ) ) ]
669
710
}
670
- } ;
671
- Some ( stmt)
672
- } )
673
- . collect ( ) ;
711
+ }
712
+ ast:: Stmt :: Item ( item) => {
713
+ self . check_cfg ( & item) ?;
714
+
715
+ return None ;
716
+ }
717
+ } ;
718
+
719
+ Some ( stmt)
720
+ }
721
+
722
+ fn collect_block ( & mut self , block : ast:: BlockExpr ) -> ExprId {
723
+ let syntax_node_ptr = AstPtr :: new ( & block. clone ( ) . into ( ) ) ;
724
+ self . collect_stmts_items ( block. statements ( ) ) ;
725
+ let statements =
726
+ block. statements ( ) . filter_map ( |s| self . collect_stmt ( s) ) . flatten ( ) . collect ( ) ;
674
727
let tail = block. expr ( ) . map ( |e| self . collect_expr ( e) ) ;
675
728
self . alloc_expr ( Expr :: Block { statements, tail, label : None } , syntax_node_ptr)
676
729
}
677
730
678
- fn collect_block_items ( & mut self , block : & ast:: BlockExpr ) {
731
+ fn collect_stmts_items ( & mut self , stmts : ast:: AstChildren < ast :: Stmt > ) {
679
732
let container = ContainerId :: DefWithBodyId ( self . def ) ;
680
733
681
- let items = block
682
- . statements ( )
734
+ let items = stmts
683
735
. filter_map ( |stmt| match stmt {
684
736
ast:: Stmt :: Item ( it) => Some ( it) ,
685
737
ast:: Stmt :: LetStmt ( _) | ast:: Stmt :: ExprStmt ( _) => None ,
0 commit comments