@@ -592,97 +592,54 @@ pub fn build_output_filenames(
592
592
//
593
593
// [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
594
594
pub struct ReplaceBodyWithLoop < ' a , ' b > {
595
- within_static_or_const : bool ,
595
+ ignore_item : bool ,
596
596
nested_blocks : Option < Vec < ast:: Block > > ,
597
597
resolver : & ' a mut Resolver < ' b > ,
598
598
}
599
599
600
600
impl < ' a , ' b > ReplaceBodyWithLoop < ' a , ' b > {
601
601
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 }
603
603
}
604
604
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 ) ;
607
607
let old_blocks = self . nested_blocks . take ( ) ;
608
608
let ret = action ( self ) ;
609
- self . within_static_or_const = old_const ;
609
+ self . ignore_item = old_ignore_item ;
610
610
self . nested_blocks = old_blocks;
611
611
ret
612
612
}
613
613
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( ) )
661
617
}
662
618
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 ( ..) )
666
623
}
667
624
}
668
625
669
626
impl < ' a > MutVisitor for ReplaceBodyWithLoop < ' a , ' _ > {
670
627
fn visit_item_kind ( & mut self , i : & mut ast:: ItemKind ) {
671
- let is_const = match i {
628
+ let ignore_item = match i {
672
629
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) ,
674
631
_ => false ,
675
632
} ;
676
- self . run ( is_const , |s| noop_visit_item_kind ( i, s) )
633
+ self . run ( ignore_item , |s| noop_visit_item_kind ( i, s) )
677
634
}
678
635
679
636
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 {
681
638
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) ,
683
640
_ => false ,
684
641
} ;
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) )
686
643
}
687
644
688
645
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, '_> {
693
650
self . run ( true , |s| noop_visit_anon_const ( c, s) )
694
651
}
695
652
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
+
696
722
fn visit_block ( & mut self , b : & mut P < ast:: Block > ) {
697
723
fn stmt_to_block (
698
724
rules : ast:: BlockCheckMode ,
@@ -723,6 +749,11 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
723
749
}
724
750
}
725
751
752
+ if self . ignore_item {
753
+ noop_visit_block ( b, self ) ;
754
+ return ;
755
+ }
756
+
726
757
let empty_block = stmt_to_block ( BlockCheckMode :: Default , None , self . resolver ) ;
727
758
let loop_expr = P ( ast:: Expr {
728
759
kind : ast:: ExprKind :: Loop ( P ( empty_block) , None ) ,
@@ -738,39 +769,41 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
738
769
kind : ast:: StmtKind :: Expr ( loop_expr) ,
739
770
} ;
740
771
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
+ }
748
790
749
- stmts. extend ( self . flat_map_stmt ( s ) . into_iter ( ) . filter ( |s| s . is_item ( ) ) ) ;
791
+ let mut new_block = ast :: Block { stmts, ..b } ;
750
792
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 ) ;
755
797
}
756
798
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) ;
769
803
770
- new_block
771
- }
772
- } )
773
- }
804
+ new_block
805
+ }
806
+ } )
774
807
}
775
808
776
809
// in general the pretty printer processes unexpanded code, so
0 commit comments