@@ -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