@@ -592,97 +592,54 @@ pub fn build_output_filenames(
592592// 
593593// [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401 
594594pub  struct  ReplaceBodyWithLoop < ' a ,  ' b >  { 
595-     within_static_or_const :  bool , 
595+     ignore_item :  bool , 
596596    nested_blocks :  Option < Vec < ast:: Block > > , 
597597    resolver :  & ' a  mut  Resolver < ' b > , 
598598} 
599599
600600impl < ' a ,  ' b >  ReplaceBodyWithLoop < ' a ,  ' b >  { 
601601    pub  fn  new ( resolver :  & ' a  mut  Resolver < ' b > )  -> ReplaceBodyWithLoop < ' a ,  ' b >  { 
602-         ReplaceBodyWithLoop  {  within_static_or_const :  false ,  nested_blocks :  None ,  resolver } 
602+         ReplaceBodyWithLoop  {  ignore_item :  false ,  nested_blocks :  None ,  resolver } 
603603    } 
604604
605-     fn  run < R ,  F :  FnOnce ( & mut  Self )  -> R > ( & mut  self ,  is_const :  bool ,  action :  F )  -> R  { 
606-         let  old_const  = mem:: replace ( & mut  self . within_static_or_const ,  is_const ) ; 
605+     fn  run < R ,  F :  FnOnce ( & mut  Self )  -> R > ( & mut  self ,  ignore_item :  bool ,  action :  F )  -> R  { 
606+         let  old_ignore_item  = mem:: replace ( & mut  self . ignore_item ,  ignore_item ) ; 
607607        let  old_blocks = self . nested_blocks . take ( ) ; 
608608        let  ret = action ( self ) ; 
609-         self . within_static_or_const  = old_const ; 
609+         self . ignore_item  = old_ignore_item ; 
610610        self . nested_blocks  = old_blocks; 
611611        ret
612612    } 
613613
614-     fn  should_ignore_fn ( ret_ty :  & ast:: FnRetTy )  -> bool  { 
615-         if  let  ast:: FnRetTy :: Ty ( ref  ty)  = ret_ty { 
616-             fn  involves_impl_trait ( ty :  & ast:: Ty )  -> bool  { 
617-                 match  ty. kind  { 
618-                     ast:: TyKind :: ImplTrait ( ..)  => true , 
619-                     ast:: TyKind :: Slice ( ref  subty) 
620-                     | ast:: TyKind :: Array ( ref  subty,  _) 
621-                     | ast:: TyKind :: Ptr ( ast:: MutTy  {  ty :  ref  subty,  .. } ) 
622-                     | ast:: TyKind :: Rptr ( _,  ast:: MutTy  {  ty :  ref  subty,  .. } ) 
623-                     | ast:: TyKind :: Paren ( ref  subty)  => involves_impl_trait ( subty) , 
624-                     ast:: TyKind :: Tup ( ref  tys)  => any_involves_impl_trait ( tys. iter ( ) ) , 
625-                     ast:: TyKind :: Path ( _,  ref  path)  => { 
626-                         path. segments . iter ( ) . any ( |seg| match  seg. args . as_deref ( )  { 
627-                             None  => false , 
628-                             Some ( & ast:: GenericArgs :: AngleBracketed ( ref  data) )  => { 
629-                                 data. args . iter ( ) . any ( |arg| match  arg { 
630-                                     ast:: AngleBracketedArg :: Arg ( arg)  => match  arg { 
631-                                         ast:: GenericArg :: Type ( ty)  => involves_impl_trait ( ty) , 
632-                                         ast:: GenericArg :: Lifetime ( _) 
633-                                         | ast:: GenericArg :: Const ( _)  => false , 
634-                                     } , 
635-                                     ast:: AngleBracketedArg :: Constraint ( c)  => match  c. kind  { 
636-                                         ast:: AssocTyConstraintKind :: Bound  {  .. }  => true , 
637-                                         ast:: AssocTyConstraintKind :: Equality  {  ref  ty }  => { 
638-                                             involves_impl_trait ( ty) 
639-                                         } 
640-                                     } , 
641-                                 } ) 
642-                             } 
643-                             Some ( & ast:: GenericArgs :: Parenthesized ( ref  data) )  => { 
644-                                 any_involves_impl_trait ( data. inputs . iter ( ) ) 
645-                                     || ReplaceBodyWithLoop :: should_ignore_fn ( & data. output ) 
646-                             } 
647-                         } ) 
648-                     } 
649-                     _ => false , 
650-                 } 
651-             } 
652- 
653-             fn  any_involves_impl_trait < ' a ,  I :  Iterator < Item  = & ' a  P < ast:: Ty > > > ( mut  it :  I )  -> bool  { 
654-                 it. any ( |subty| involves_impl_trait ( subty) ) 
655-             } 
656- 
657-             involves_impl_trait ( ty) 
658-         }  else  { 
659-             false 
660-         } 
614+     fn  should_ignore_fn ( sig :  & ast:: FnSig )  -> bool  { 
615+         matches ! ( sig. header. constness,  ast:: Const :: Yes ( _) ) 
616+             || matches ! ( & sig. decl. output,  ast:: FnRetTy :: Ty ( ty)  if  ty. contains_impl_trait( ) ) 
661617    } 
662618
663-     fn  is_sig_const ( sig :  & ast:: FnSig )  -> bool  { 
664-         matches ! ( sig. header. constness,  ast:: Const :: Yes ( _) ) 
665-             || ReplaceBodyWithLoop :: should_ignore_fn ( & sig. decl . output ) 
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 ( ..) ) 
666623    } 
667624} 
668625
669626impl < ' a >  MutVisitor  for  ReplaceBodyWithLoop < ' a ,  ' _ >  { 
670627    fn  visit_item_kind ( & mut  self ,  i :  & mut  ast:: ItemKind )  { 
671-         let  is_const  = match  i { 
628+         let  ignore_item  = match  i { 
672629            ast:: ItemKind :: Static ( ..)  | ast:: ItemKind :: Const ( ..)  => true , 
673-             ast:: ItemKind :: Fn ( _,  ref  sig,  _,  _)  => Self :: is_sig_const ( sig) , 
630+             ast:: ItemKind :: Fn ( _,  ref  sig,  _,  _)  => Self :: should_ignore_fn ( sig) , 
674631            _ => false , 
675632        } ; 
676-         self . run ( is_const ,  |s| noop_visit_item_kind ( i,  s) ) 
633+         self . run ( ignore_item ,  |s| noop_visit_item_kind ( i,  s) ) 
677634    } 
678635
679636    fn  flat_map_trait_item ( & mut  self ,  i :  P < ast:: AssocItem > )  -> SmallVec < [ P < ast:: AssocItem > ;  1 ] >  { 
680-         let  is_const  = match  i. kind  { 
637+         let  ignore_item  = match  i. kind  { 
681638            ast:: AssocItemKind :: Const ( ..)  => true , 
682-             ast:: AssocItemKind :: Fn ( _,  ref  sig,  _,  _)  => Self :: is_sig_const ( sig) , 
639+             ast:: AssocItemKind :: Fn ( _,  ref  sig,  _,  _)  => Self :: should_ignore_fn ( sig) , 
683640            _ => false , 
684641        } ; 
685-         self . run ( is_const ,  |s| noop_flat_map_assoc_item ( i,  s) ) 
642+         self . run ( ignore_item ,  |s| noop_flat_map_assoc_item ( i,  s) ) 
686643    } 
687644
688645    fn  flat_map_impl_item ( & mut  self ,  i :  P < ast:: AssocItem > )  -> SmallVec < [ P < ast:: AssocItem > ;  1 ] >  { 
@@ -693,6 +650,75 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
693650        self . run ( true ,  |s| noop_visit_anon_const ( c,  s) ) 
694651    } 
695652
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+ 
696722    fn  visit_block ( & mut  self ,  b :  & mut  P < ast:: Block > )  { 
697723        fn  stmt_to_block ( 
698724            rules :  ast:: BlockCheckMode , 
@@ -723,6 +749,11 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
723749            } 
724750        } 
725751
752+         if  self . ignore_item  { 
753+             noop_visit_block ( b,  self ) ; 
754+             return ; 
755+         } 
756+ 
726757        let  empty_block = stmt_to_block ( BlockCheckMode :: Default ,  None ,  self . resolver ) ; 
727758        let  loop_expr = P ( ast:: Expr  { 
728759            kind :  ast:: ExprKind :: Loop ( P ( empty_block) ,  None ) , 
@@ -738,39 +769,41 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
738769            kind :  ast:: StmtKind :: Expr ( loop_expr) , 
739770        } ; 
740771
741-         if  self . within_static_or_const  { 
742-             noop_visit_block ( b,  self ) 
743-         }  else  { 
744-             visit_clobber ( b. deref_mut ( ) ,  |b| { 
745-                 let  mut  stmts = vec ! [ ] ; 
746-                 for  s in  b. stmts  { 
747-                     let  old_blocks = self . nested_blocks . replace ( vec ! [ ] ) ; 
772+         visit_clobber ( b. deref_mut ( ) ,  |b| { 
773+             let  mut  stmts = vec ! [ ] ; 
774+             for  s in  b. stmts  { 
775+                 let  old_blocks = self . nested_blocks . replace ( vec ! [ ] ) ; 
776+ 
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+                 } ) ) ; 
784+ 
785+                 // we put a Some in there earlier with that replace(), so this is valid 
786+                 let  new_blocks = self . nested_blocks . take ( ) . unwrap ( ) ; 
787+                 self . nested_blocks  = old_blocks; 
788+                 stmts. extend ( new_blocks. into_iter ( ) . map ( |b| block_to_stmt ( b,  self . resolver ) ) ) ; 
789+             } 
748790
749-                      stmts. extend ( self . flat_map_stmt ( s ) . into_iter ( ) . filter ( |s| s . is_item ( ) ) ) ; 
791+             let   mut  new_block = ast :: Block   {   stmts,  ..b  } ; 
750792
751-                      // we put a  Some in there earlier with that replace(), so this is valid 
752-                      let  new_blocks =  self . nested_blocks . take ( ) . unwrap ( ) ; 
753-                      self . nested_blocks  = old_blocks ; 
754-                     stmts . extend ( new_blocks . into_iter ( ) . map ( |b|  block_to_stmt ( b ,   self . resolver ) ) ) ; 
793+             if   let   Some ( old_blocks )  =  self . nested_blocks . as_mut ( )   { 
794+                 //push our fresh block onto the cache and yield an empty block with `loop {}` 
795+                 if  !new_block . stmts . is_empty ( )   { 
796+                     old_blocks . push ( new_block ) ; 
755797                } 
756798
757-                 let  mut  new_block = ast:: Block  {  stmts,  ..b } ; 
758- 
759-                 if  let  Some ( old_blocks)  = self . nested_blocks . as_mut ( )  { 
760-                     //push our fresh block onto the cache and yield an empty block with `loop {}` 
761-                     if  !new_block. stmts . is_empty ( )  { 
762-                         old_blocks. push ( new_block) ; 
763-                     } 
764- 
765-                     stmt_to_block ( b. rules ,  Some ( loop_stmt) ,  & mut  self . resolver ) 
766-                 }  else  { 
767-                     //push `loop {}` onto the end of our fresh block and yield that 
768-                     new_block. stmts . push ( loop_stmt) ; 
799+                 stmt_to_block ( b. rules ,  Some ( loop_stmt) ,  & mut  self . resolver ) 
800+             }  else  { 
801+                 //push `loop {}` onto the end of our fresh block and yield that 
802+                 new_block. stmts . push ( loop_stmt) ; 
769803
770-                     new_block
771-                 } 
772-             } ) 
773-         } 
804+                 new_block
805+             } 
806+         } ) 
774807    } 
775808
776809    // in general the pretty printer processes unexpanded code, so 
0 commit comments