7
7
8
8
use std:: collections:: VecDeque ;
9
9
10
- use either:: Either ;
11
10
use rustc_data_structures:: fx:: FxHashSet ;
12
11
use rustc_data_structures:: graph:: scc:: { self , Sccs } ;
13
12
use rustc_index:: IndexVec ;
@@ -17,7 +16,6 @@ use rustc_infer::infer::relate::TypeRelation;
17
16
use rustc_middle:: bug;
18
17
use rustc_middle:: ty:: relate:: { self , Relate , RelateResult } ;
19
18
use rustc_middle:: ty:: { self , Region , RegionVid , Ty , TyCtxt , UniverseIndex } ;
20
- use rustc_span:: Span ;
21
19
use tracing:: { debug, instrument, trace} ;
22
20
23
21
use crate :: ConstraintCategory ;
@@ -26,15 +24,15 @@ use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
26
24
use crate :: consumers:: OutlivesConstraint ;
27
25
use crate :: diagnostics:: { RegionErrorKind , RegionErrors } ;
28
26
use crate :: member_constraints:: MemberConstraintSet ;
29
- use crate :: region_infer:: { RegionDefinition , Representative , TypeTest } ;
27
+ use crate :: region_infer:: { RegionDefinition , Representative , TypeTest , TypeTestOrigin } ;
30
28
use crate :: ty:: VarianceDiagInfo ;
31
29
use crate :: type_check:: Locations ;
32
30
use crate :: universal_regions:: UniversalRegions ;
33
31
34
32
/// A set of outlives constraints after rewriting to remove
35
33
/// higher-kinded constraints.
36
34
pub ( crate ) struct LoweredConstraints < ' tcx > {
37
- pub ( crate ) type_tests : Vec < LoweredTypeTest < ' tcx > > ,
35
+ pub ( crate ) type_tests : Vec < TypeTest < ' tcx > > ,
38
36
pub ( crate ) sccs : Sccs < RegionVid , ConstraintSccIndex > ,
39
37
pub ( crate ) definitions : IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
40
38
pub ( crate ) scc_representatives : IndexVec < ConstraintSccIndex , Representative > ,
@@ -463,10 +461,7 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
463
461
& mut annotations,
464
462
) ;
465
463
return LoweredConstraints {
466
- type_tests : type_tests
467
- . into_iter ( )
468
- . map ( |type_test| LoweredTypeTest :: Untouched ( type_test) )
469
- . collect ( ) ,
464
+ type_tests, // Pass them through unmodified.
470
465
member_constraints : member_constraints. into_mapped (
471
466
|r| sccs. scc ( r) ,
472
467
|_| true ,
@@ -670,158 +665,121 @@ fn find_region<'tcx>(
670
665
bug ! ( "Should have found something!" ) ;
671
666
}
672
667
673
- #[ derive( Debug , Clone ) ]
674
- pub ( crate ) enum RewrittenVerifyBound < ' tcx > {
675
- AnyBound ( Vec < Either < VerifyBound < ' tcx > , RewrittenVerifyBound < ' tcx > > > ) ,
676
- AllBounds ( Vec < Either < VerifyBound < ' tcx > , RewrittenVerifyBound < ' tcx > > > ) ,
677
-
678
- /// Given a region `R`, true if `R: 'static`. Used during lowering
679
- /// of higher-kinded constraints.
680
- OutlivesStatic ( Region < ' tcx > ) ,
681
-
682
- /// The bottom bound, which is never satisfied.
683
- Unsatisfied ,
684
- }
685
-
686
- /// A type test rewritten to handle higher-kinded concerns.
687
- #[ derive( Debug , Clone ) ]
688
- pub ( crate ) enum LoweredTypeTest < ' tcx > {
689
- Untouched ( TypeTest < ' tcx > ) ,
690
- Rewritten {
691
- rewritten_bound : RewrittenVerifyBound < ' tcx > ,
692
- /// The type `T` that must outlive the region.
693
- generic_kind : GenericKind < ' tcx > ,
694
-
695
- /// The region `'x` that the type must outlive.
696
- lower_bound : RegionVid ,
697
-
698
- /// The span to blame.
699
- span : Span ,
700
- } ,
668
+ struct TypeTestRewriter < ' c , ' tcx > {
669
+ lower_scc : ConstraintSccIndex ,
670
+ sccs : & ' c Sccs < RegionVid , ConstraintSccIndex > ,
671
+ scc_annotations : & ' c IndexVec < ConstraintSccIndex , RegionTracker > ,
672
+ universal_regions : & ' c UniversalRegions < ' tcx > ,
673
+ tcx : TyCtxt < ' tcx > ,
674
+ generic_kind : GenericKind < ' tcx > ,
701
675
}
702
676
703
- #[ instrument( skip( sccs, scc_annotations, universal_regions, tcx) , ret) ]
704
- fn rewrite_verify_bound < ' t > (
705
- bound : VerifyBound < ' t > ,
706
- lower_scc : ConstraintSccIndex ,
707
- sccs : & Sccs < RegionVid , ConstraintSccIndex > ,
708
- scc_annotations : & IndexVec < ConstraintSccIndex , RegionTracker > ,
709
- universal_regions : & UniversalRegions < ' t > ,
710
- tcx : TyCtxt < ' t > ,
711
- generic_kind : GenericKind < ' t > ,
712
- ) -> Either < VerifyBound < ' t > , RewrittenVerifyBound < ' t > > {
713
- let lower = scc_annotations[ lower_scc] ;
714
- match bound {
715
- // You may think that an equality bound would imply universe
716
- // equality, and it does -- except that we do not track placeholders,
717
- // and so in the event that you have two empty regions, one of which is
718
- // in an unnameable universe, they would compare equal since they
719
- // are both empty. This bit ensures that whatever comes out of the
720
- // bound also matches the placeholder reachability of the lower bound.
721
- VerifyBound :: IfEq ( verify_if_eq_b) => {
722
- // this bit picks out the worst possible candidate that can end up for the match
723
- // in terms of its universe.
724
- let mut m = MatchUniverses :: new ( tcx, sccs, scc_annotations, universal_regions) ;
725
- let verify_if_eq = verify_if_eq_b. skip_binder ( ) ;
726
- let what_error = m. relate ( verify_if_eq. ty , generic_kind. to_ty ( tcx) ) ;
727
- if let Err ( e) = what_error {
728
- debug ! ( "Type test {verify_if_eq_b:?} {generic_kind:?} failed to match with {e:?}" ) ;
729
- return Either :: Right ( RewrittenVerifyBound :: Unsatisfied ) ;
677
+ impl < ' c , ' tcx > TypeTestRewriter < ' c , ' tcx > {
678
+ fn annotation ( & self , rvid : RegionVid ) -> RegionTracker {
679
+ self . scc_annotations [ self . sccs . scc ( rvid) ]
680
+ }
681
+
682
+ /// Determine if a region is compatible with the lower bound's
683
+ /// universe.
684
+ fn universe_compatible_with_bound ( & self , r : Region < ' tcx > ) -> bool {
685
+ let rvid = self . universal_regions . to_region_vid ( r) ;
686
+ rvid == self . universal_regions . fr_static
687
+ || self . annotation ( rvid) . universe_compatible_with ( self . scc_annotations [ self . lower_scc ] )
688
+ }
689
+
690
+ #[ instrument( skip( self ) , ret) ]
691
+ fn rewrite ( & self , bound : & VerifyBound < ' tcx > ) -> Option < VerifyBound < ' tcx > > {
692
+ let lower = self . scc_annotations [ self . lower_scc ] ;
693
+ match bound {
694
+ // You may think that an equality bound would imply universe
695
+ // equality, and it does -- except that we do not track placeholders,
696
+ // and so in the event that you have two empty regions, one of which is
697
+ // in an unnameable universe, they would compare equal since they
698
+ // are both empty. This bit ensures that whatever comes out of the
699
+ // bound also matches the placeholder reachability of the lower bound.
700
+ VerifyBound :: IfEq ( verify_if_eq_b) => {
701
+ // this bit picks out the worst possible candidate that can end up for the match
702
+ // in terms of its universe.
703
+ let mut m = MatchUniverses :: new (
704
+ self . tcx ,
705
+ self . sccs ,
706
+ self . scc_annotations ,
707
+ self . universal_regions ,
708
+ ) ;
709
+ let verify_if_eq = verify_if_eq_b. skip_binder ( ) ;
710
+ let what_error = m. relate ( verify_if_eq. ty , self . generic_kind . to_ty ( self . tcx ) ) ;
711
+ if let Err ( e) = what_error {
712
+ debug ! (
713
+ "Type test {verify_if_eq_b:?} {generic_kind:?} failed to match with {e:?}" ,
714
+ generic_kind = self . generic_kind
715
+ ) ;
716
+ return Some ( VerifyBound :: never_satisfied ( ) ) ;
717
+ }
718
+
719
+ let r = if let ty:: RegionKind :: ReBound ( depth, _) = verify_if_eq. bound . kind ( ) {
720
+ assert ! ( depth == ty:: INNERMOST ) ;
721
+ m. max_universe_region . map_or ( self . tcx . lifetimes . re_static , |pair| pair. 1 )
722
+ } else {
723
+ verify_if_eq. bound
724
+ } ;
725
+
726
+ if self . universe_compatible_with_bound ( r) {
727
+ None
728
+ } else {
729
+ Some ( VerifyBound :: never_satisfied ( ) )
730
+ }
731
+ }
732
+ // Rewrite an outlives bound to an outlives-static bound upon referencing
733
+ // an unnameable universe (from a placeholder).
734
+ VerifyBound :: OutlivedBy ( region) => {
735
+ if self . universe_compatible_with_bound ( * region) {
736
+ None
737
+ } else {
738
+ Some ( VerifyBound :: OutlivesStatic ( * region) )
739
+ }
740
+ }
741
+ // Nothing in here to violate a universe, but since we can't detect
742
+ // bounds being violated by placeholders when we don't track placeholders,
743
+ // we ensure that we don't reach any.
744
+ VerifyBound :: IsEmpty => {
745
+ if matches ! ( lower. reachable_placeholders, PlaceholderReachability :: NoPlaceholders ) {
746
+ None
747
+ } else {
748
+ debug ! ( "Empty bound reaches placeholders: {:?}" , lower. reachable_placeholders) ;
749
+ Some ( VerifyBound :: never_satisfied ( ) )
750
+ }
751
+ }
752
+ VerifyBound :: AnyBound ( verify_bounds) => {
753
+ self . rewrite_bounds ( verify_bounds) . map ( VerifyBound :: AnyBound )
730
754
}
731
755
732
- let r = if let ty:: RegionKind :: ReBound ( depth, _) = verify_if_eq. bound . kind ( ) {
733
- assert ! ( depth == ty:: INNERMOST ) ;
734
- m. max_universe_region . map_or ( tcx. lifetimes . re_static , |pair| pair. 1 )
735
- } else {
736
- verify_if_eq. bound
737
- } ;
738
-
739
- let l_scc = scc_annotations[ lower_scc] ;
740
- let rvid = universal_regions. to_region_vid ( r) ;
741
-
742
- if rvid == universal_regions. fr_static
743
- || scc_annotations[ sccs. scc ( rvid) ] . universe_compatible_with ( l_scc)
744
- {
745
- Either :: Left ( bound)
746
- } else {
747
- Either :: Right ( RewrittenVerifyBound :: Unsatisfied )
756
+ VerifyBound :: AllBounds ( verify_bounds) => {
757
+ self . rewrite_bounds ( verify_bounds) . map ( VerifyBound :: AllBounds )
748
758
}
749
- }
750
- // Rewrite an outlives bound to an outlives-static bound upon referencing
751
- // an unnameable universe (from a placeholder).
752
- VerifyBound :: OutlivedBy ( region) => {
753
- let rvid = universal_regions. to_region_vid ( region) ;
754
- if rvid == universal_regions. fr_static
755
- || scc_annotations[ sccs. scc ( rvid) ] . universe_compatible_with ( lower)
756
- {
757
- either:: Left ( bound)
758
- } else {
759
- Either :: Right ( RewrittenVerifyBound :: OutlivesStatic ( region) )
759
+ VerifyBound :: OutlivesStatic ( _) => {
760
+ bug ! ( "Unexpected OutlivesStatic bound; they should not have been introduced yet!" )
760
761
}
761
762
}
762
- // Nothing in here to violate a universe, but since we can't detect
763
- // bounds being violated by placeholders when we don't track placeholders,
764
- // we ensure that we don't reach any.
765
- VerifyBound :: IsEmpty => {
766
- if matches ! ( lower. reachable_placeholders, PlaceholderReachability :: NoPlaceholders ) {
767
- Either :: Left ( bound)
763
+ }
764
+
765
+ fn rewrite_bounds (
766
+ & self ,
767
+ verify_bounds : & Vec < VerifyBound < ' tcx > > ,
768
+ ) -> Option < Vec < VerifyBound < ' tcx > > > {
769
+ let mut bounds = Vec :: with_capacity ( verify_bounds. len ( ) ) ;
770
+ let mut rewrote_any = false ;
771
+ for bound in verify_bounds {
772
+ let bound = if let Some ( rewritten) = self . rewrite ( & bound) {
773
+ rewrote_any = true ;
774
+ rewritten
768
775
} else {
769
- debug ! ( "Empty bound reaches placeholders: {:?}" , lower. reachable_placeholders) ;
770
- Either :: Right ( RewrittenVerifyBound :: Unsatisfied )
771
- }
772
- }
773
- // It's tempting to try to rewrite this or the next one to be able to
774
- // return the regular bounds if in fact none of them needed rewriting,
775
- // but for reasons of "computer is dumb" this is trickier than you may think.
776
- VerifyBound :: AnyBound ( verify_bounds) => {
777
- either:: Right ( RewrittenVerifyBound :: AnyBound ( rewrite_verify_bounds (
778
- verify_bounds,
779
- lower_scc,
780
- sccs,
781
- scc_annotations,
782
- universal_regions,
783
- tcx,
784
- generic_kind,
785
- ) ) )
786
- }
787
- VerifyBound :: AllBounds ( verify_bounds) => {
788
- either:: Right ( RewrittenVerifyBound :: AllBounds ( rewrite_verify_bounds (
789
- verify_bounds,
790
- lower_scc,
791
- sccs,
792
- scc_annotations,
793
- universal_regions,
794
- tcx,
795
- generic_kind,
796
- ) ) )
776
+ bound. clone ( )
777
+ } ;
778
+ bounds. push ( bound) ;
797
779
}
798
- }
799
- }
800
780
801
- // FIXME This is crying out for a TypeTestRewritingContext.
802
- fn rewrite_verify_bounds < ' t > (
803
- verify_bounds : Vec < VerifyBound < ' t > > ,
804
- lower_scc : ConstraintSccIndex ,
805
- sccs : & Sccs < RegionVid , ConstraintSccIndex > ,
806
- scc_annotations : & IndexVec < ConstraintSccIndex , RegionTracker > ,
807
- universal_regions : & UniversalRegions < ' t > ,
808
- tcx : TyCtxt < ' t > ,
809
- generic_kind : GenericKind < ' t > ,
810
- ) -> Vec < Either < VerifyBound < ' t > , RewrittenVerifyBound < ' t > > > {
811
- verify_bounds
812
- . into_iter ( )
813
- . map ( |bound| {
814
- rewrite_verify_bound (
815
- bound,
816
- lower_scc,
817
- sccs,
818
- scc_annotations,
819
- universal_regions,
820
- tcx,
821
- generic_kind,
822
- )
823
- } )
824
- . collect ( )
781
+ if rewrote_any { Some ( bounds) } else { None }
782
+ }
825
783
}
826
784
827
785
impl < ' t > TypeTest < ' t > {
@@ -832,26 +790,25 @@ impl<'t> TypeTest<'t> {
832
790
scc_annotations : & IndexVec < ConstraintSccIndex , RegionTracker > ,
833
791
universal_regions : & UniversalRegions < ' t > ,
834
792
tcx : TyCtxt < ' t > ,
835
- ) -> LoweredTypeTest < ' t > {
836
- let lower_scc = sccs. scc ( self . lower_bound ) ;
837
- match rewrite_verify_bound (
838
- self . verify_bound ,
839
- lower_scc,
793
+ ) -> Self {
794
+ let rewriter = TypeTestRewriter {
795
+ generic_kind : self . generic_kind ,
840
796
sccs,
841
797
scc_annotations,
842
798
universal_regions,
843
799
tcx,
844
- self . generic_kind ,
845
- ) {
846
- Either :: Left ( untouched_bound) => {
847
- LoweredTypeTest :: Untouched ( TypeTest { verify_bound : untouched_bound, ..self } )
848
- }
849
- Either :: Right ( rewritten_bound) => LoweredTypeTest :: Rewritten {
850
- rewritten_bound,
800
+ lower_scc : sccs. scc ( self . lower_bound ) ,
801
+ } ;
802
+
803
+ if let Some ( rewritten_bound) = rewriter. rewrite ( & self . verify_bound ) {
804
+ TypeTest {
805
+ verify_bound : rewritten_bound,
851
806
generic_kind : self . generic_kind ,
852
807
lower_bound : self . lower_bound ,
853
- span : self . span ,
854
- } ,
808
+ source : TypeTestOrigin :: Rewritten ( Box :: new ( self ) ) ,
809
+ }
810
+ } else {
811
+ self
855
812
}
856
813
}
857
814
}
0 commit comments