@@ -615,6 +615,12 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
615615 matches ! ( sig. header. constness, ast:: Const :: Yes ( _) )
616616 || matches ! ( & sig. decl. output, ast:: FnRetTy :: Ty ( ty) if ty. contains_impl_trait( ) )
617617 }
618+
619+ /// Keep some `Expr`s that are ultimately assigned `DefId`s. This keeps the `HirId` parent
620+ /// mappings correct even after this pass runs.
621+ fn should_preserve_expr ( e : & ast:: Expr ) -> bool {
622+ matches ! ( & e. kind, ast:: ExprKind :: Closure ( ..) | ast:: ExprKind :: Async ( ..) )
623+ }
618624}
619625
620626impl < ' a > MutVisitor for ReplaceBodyWithLoop < ' a , ' _ > {
@@ -644,6 +650,75 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
644650 self . run ( true , |s| noop_visit_anon_const ( c, s) )
645651 }
646652
653+ fn filter_map_expr ( & mut self , mut e : P < ast:: Expr > ) -> Option < P < ast:: Expr > > {
654+ if self . ignore_item {
655+ return noop_filter_map_expr ( e, self ) ;
656+ }
657+
658+ if let ast:: ExprKind :: Closure ( .., decl, expr, _) = & mut e. kind {
659+ // Replacing a closure body and removing its callsites will break inference. Give
660+ // all closures the signature `|| -> !` to work around this.
661+ decl. inputs = vec ! [ ] ;
662+ if let ast:: FnRetTy :: Default ( _) = decl. output {
663+ decl. output = ast:: FnRetTy :: Ty ( P ( ast:: Ty {
664+ id : self . resolver . next_node_id ( ) ,
665+ span : rustc_span:: DUMMY_SP ,
666+ kind : ast:: TyKind :: Never ,
667+ } ) ) ;
668+ }
669+
670+ // Replace `|| expr` with `|| { expr }` so that `visit_block` gets called on the
671+ // closure body.
672+ if !matches ! ( expr. kind, ast:: ExprKind :: Block ( ..) ) {
673+ let new_stmt = ast:: Stmt {
674+ kind : ast:: StmtKind :: Expr ( expr. clone ( ) ) ,
675+ id : self . resolver . next_node_id ( ) ,
676+ span : expr. span ,
677+ } ;
678+
679+ let new_block = ast:: Block {
680+ stmts : vec ! [ new_stmt] ,
681+ rules : BlockCheckMode :: Default ,
682+ id : self . resolver . next_node_id ( ) ,
683+ span : expr. span ,
684+ } ;
685+
686+ expr. kind = ast:: ExprKind :: Block ( P ( new_block) , None ) ;
687+ }
688+ }
689+
690+ if Self :: should_preserve_expr ( & e) {
691+ self . run ( false , |s| noop_filter_map_expr ( e, s) )
692+ } else {
693+ noop_filter_map_expr ( e, self )
694+ }
695+ }
696+
697+ fn flat_map_stmt ( & mut self , s : ast:: Stmt ) -> SmallVec < [ ast:: Stmt ; 1 ] > {
698+ if self . ignore_item {
699+ return noop_flat_map_stmt ( s, self ) ;
700+ }
701+
702+ let ast:: Stmt { id, span, .. } = s;
703+ match s. kind {
704+ // Replace `let x = || {};` with `|| {};`
705+ ast:: StmtKind :: Local ( mut local) if local. init . is_some ( ) => self
706+ . filter_map_expr ( local. init . take ( ) . unwrap ( ) )
707+ . into_iter ( )
708+ . map ( |e| ast:: Stmt { kind : ast:: StmtKind :: Semi ( e) , id, span } )
709+ . collect ( ) ,
710+
711+ // Replace `|| {}` with `|| {};`
712+ ast:: StmtKind :: Expr ( expr) => self
713+ . filter_map_expr ( expr)
714+ . into_iter ( )
715+ . map ( |e| ast:: Stmt { kind : ast:: StmtKind :: Semi ( e) , id, span } )
716+ . collect ( ) ,
717+
718+ _ => noop_flat_map_stmt ( s, self ) ,
719+ }
720+ }
721+
647722 fn visit_block ( & mut self , b : & mut P < ast:: Block > ) {
648723 fn stmt_to_block (
649724 rules : ast:: BlockCheckMode ,
@@ -699,7 +774,13 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
699774 for s in b. stmts {
700775 let old_blocks = self . nested_blocks . replace ( vec ! [ ] ) ;
701776
702- stmts. extend ( self . flat_map_stmt ( s) . into_iter ( ) . filter ( |s| s. is_item ( ) ) ) ;
777+ stmts. extend ( self . flat_map_stmt ( s) . into_iter ( ) . filter ( |s| {
778+ s. is_item ( )
779+ || matches ! (
780+ & s. kind,
781+ ast:: StmtKind :: Semi ( expr) if Self :: should_preserve_expr( expr)
782+ )
783+ } ) ) ;
703784
704785 // we put a Some in there earlier with that replace(), so this is valid
705786 let new_blocks = self . nested_blocks . take ( ) . unwrap ( ) ;
0 commit comments