@@ -548,62 +548,83 @@ impl ExprCollector<'_> {
548548 }
549549 }
550550 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+ }
591562
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) ;
605625 }
606626 }
627+ None => collector ( self , None ) ,
607628 }
608629 }
609630 }
@@ -642,44 +663,75 @@ impl ExprCollector<'_> {
642663 }
643664 }
644665
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) ?;
662671
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 ( ) ) ;
667690
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( ) ) ) ]
669710 }
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 ( ) ;
674727 let tail = block. expr ( ) . map ( |e| self . collect_expr ( e) ) ;
675728 self . alloc_expr ( Expr :: Block { statements, tail, label : None } , syntax_node_ptr)
676729 }
677730
678- fn collect_block_items ( & mut self , block : & ast:: BlockExpr ) {
731+ fn collect_stmts_items ( & mut self , stmts : ast:: AstChildren < ast :: Stmt > ) {
679732 let container = ContainerId :: DefWithBodyId ( self . def ) ;
680733
681- let items = block
682- . statements ( )
734+ let items = stmts
683735 . filter_map ( |stmt| match stmt {
684736 ast:: Stmt :: Item ( it) => Some ( it) ,
685737 ast:: Stmt :: LetStmt ( _) | ast:: Stmt :: ExprStmt ( _) => None ,
0 commit comments