@@ -69,6 +69,15 @@ pub struct RegionInferenceContext<'tcx> {
69
69
/// visible from this index.
70
70
scc_universes : IndexVec < ConstraintSccIndex , ty:: UniverseIndex > ,
71
71
72
+ /// Contains a "representative" from each SCC. This will be the
73
+ /// minimal RegionVid belonging to that universe. It is used as a
74
+ /// kind of hacky way to manage checking outlives relationships,
75
+ /// since we can 'canonicalize' each region to the representative
76
+ /// of its SCC and be sure that -- if they have the same repr --
77
+ /// they *must* be equal (though not having the same repr does not
78
+ /// mean they are unequal).
79
+ scc_representatives : IndexVec < ConstraintSccIndex , ty:: RegionVid > ,
80
+
72
81
/// The final inferred values of the region variables; we compute
73
82
/// one value per SCC. To get the value for any given *region*,
74
83
/// you first find which scc it is a part of.
@@ -208,13 +217,16 @@ impl<'tcx> RegionInferenceContext<'tcx> {
208
217
209
218
let scc_universes = Self :: compute_scc_universes ( & constraint_sccs, & definitions) ;
210
219
220
+ let scc_representatives = Self :: compute_scc_representatives ( & constraint_sccs, & definitions) ;
221
+
211
222
let mut result = Self {
212
223
definitions,
213
224
liveness_constraints,
214
225
constraints,
215
226
constraint_graph,
216
227
constraint_sccs,
217
228
scc_universes,
229
+ scc_representatives,
218
230
scc_values,
219
231
type_tests,
220
232
universal_regions,
@@ -251,6 +263,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
251
263
scc_universes
252
264
}
253
265
266
+ /// For each SCC, we compute a unique `RegionVid` (in fact, the
267
+ /// minimal one that belongs to the SCC). See
268
+ /// `scc_representatives` field of `RegionInferenceContext` for
269
+ /// more details.
270
+ fn compute_scc_representatives (
271
+ constraints_scc : & Sccs < RegionVid , ConstraintSccIndex > ,
272
+ definitions : & IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
273
+ ) -> IndexVec < ConstraintSccIndex , ty:: RegionVid > {
274
+ let num_sccs = constraints_scc. num_sccs ( ) ;
275
+ let next_region_vid = definitions. next_index ( ) ;
276
+ let mut scc_representatives = IndexVec :: from_elem_n ( next_region_vid, num_sccs) ;
277
+
278
+ for region_vid in definitions. indices ( ) {
279
+ let scc = constraints_scc. scc ( region_vid) ;
280
+ let prev_min = scc_representatives[ scc] ;
281
+ scc_representatives[ scc] = region_vid. min ( prev_min) ;
282
+ }
283
+
284
+ scc_representatives
285
+ }
286
+
254
287
/// Initializes the region variables for each universally
255
288
/// quantified region (lifetime parameter). The first N variables
256
289
/// always correspond to the regions appearing in the function
@@ -545,7 +578,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
545
578
for type_test in & self . type_tests {
546
579
debug ! ( "check_type_test: {:?}" , type_test) ;
547
580
548
- if self . eval_verify_bound ( mir, type_test. lower_bound , & type_test. verify_bound ) {
581
+ let generic_ty = type_test. generic_kind . to_ty ( tcx) ;
582
+ if self . eval_verify_bound (
583
+ tcx,
584
+ mir,
585
+ generic_ty,
586
+ type_test. lower_bound ,
587
+ & type_test. verify_bound ,
588
+ ) {
549
589
continue ;
550
590
}
551
591
@@ -679,7 +719,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
679
719
// where `ur` is a local bound -- we are sometimes in a
680
720
// position to prove things that our caller cannot. See
681
721
// #53570 for an example.
682
- if self . eval_verify_bound ( mir, ur, & type_test. verify_bound ) {
722
+ if self . eval_verify_bound ( tcx , mir, generic_ty , ur, & type_test. verify_bound ) {
683
723
continue ;
684
724
}
685
725
@@ -853,7 +893,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
853
893
/// `point`, and returns true or false.
854
894
fn eval_verify_bound (
855
895
& self ,
896
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
856
897
mir : & Mir < ' tcx > ,
898
+ generic_ty : Ty < ' tcx > ,
857
899
lower_bound : RegionVid ,
858
900
verify_bound : & VerifyBound < ' tcx > ,
859
901
) -> bool {
@@ -863,23 +905,85 @@ impl<'tcx> RegionInferenceContext<'tcx> {
863
905
) ;
864
906
865
907
match verify_bound {
866
- VerifyBound :: IfEq ( ..) => false , // FIXME
908
+ VerifyBound :: IfEq ( test_ty, verify_bound1) => {
909
+ self . eval_if_eq ( tcx, mir, generic_ty, lower_bound, test_ty, verify_bound1)
910
+ }
867
911
868
912
VerifyBound :: OutlivedBy ( r) => {
869
913
let r_vid = self . to_region_vid ( r) ;
870
914
self . eval_outlives ( mir, r_vid, lower_bound)
871
915
}
872
916
873
- VerifyBound :: AnyBound ( verify_bounds) => verify_bounds
874
- . iter ( )
875
- . any ( |verify_bound| self . eval_verify_bound ( mir , lower_bound , verify_bound ) ) ,
917
+ VerifyBound :: AnyBound ( verify_bounds) => verify_bounds. iter ( ) . any ( |verify_bound| {
918
+ self . eval_verify_bound ( tcx , mir , generic_ty , lower_bound , verify_bound )
919
+ } ) ,
876
920
877
- VerifyBound :: AllBounds ( verify_bounds) => verify_bounds
878
- . iter ( )
879
- . all ( |verify_bound| self . eval_verify_bound ( mir , lower_bound , verify_bound ) ) ,
921
+ VerifyBound :: AllBounds ( verify_bounds) => verify_bounds. iter ( ) . all ( |verify_bound| {
922
+ self . eval_verify_bound ( tcx , mir , generic_ty , lower_bound , verify_bound )
923
+ } ) ,
880
924
}
881
925
}
882
926
927
+ fn eval_if_eq (
928
+ & self ,
929
+ tcx : TyCtxt < ' _ , ' _ , ' tcx > ,
930
+ mir : & Mir < ' tcx > ,
931
+ generic_ty : Ty < ' tcx > ,
932
+ lower_bound : RegionVid ,
933
+ test_ty : Ty < ' tcx > ,
934
+ verify_bound : & VerifyBound < ' tcx > ,
935
+ ) -> bool {
936
+ let generic_ty_normalized = self . normalize_to_scc_representatives ( tcx, generic_ty) ;
937
+ let test_ty_normalized = self . normalize_to_scc_representatives ( tcx, test_ty) ;
938
+ if generic_ty_normalized == test_ty_normalized {
939
+ self . eval_verify_bound ( tcx, mir, generic_ty, lower_bound, verify_bound)
940
+ } else {
941
+ false
942
+ }
943
+ }
944
+
945
+ /// This is a conservative normalization procedure. It takes every
946
+ /// free region in `value` and replaces it with the
947
+ /// "representative" of its SCC (see `scc_representatives` field).
948
+ /// We are guaranteed that if two values normalize to the same
949
+ /// thing, then they are equal; this is a conservative check in
950
+ /// that they could still be equal even if they normalize to
951
+ /// different results. (For example, there might be two regions
952
+ /// with the same value that are not in the same SCC).
953
+ ///
954
+ /// NB. This is not an ideal approach and I would like to revisit
955
+ /// it. However, it works pretty well in practice. In particular,
956
+ /// this is needed to deal with projection outlives bounds like
957
+ ///
958
+ /// <T as Foo<'0>>::Item: '1
959
+ ///
960
+ /// In particular, this routine winds up being important when
961
+ /// there are bounds like `where <T as Foo<'a>>::Item: 'b` in the
962
+ /// environment. In this case, if we can show that `'0 == 'a`,
963
+ /// and that `'b: '1`, then we know that the clause is
964
+ /// satisfied. In such cases, particularly due to limitations of
965
+ /// the trait solver =), we usually wind up with a where-clause like
966
+ /// `T: Foo<'a>` in scope, which thus forces `'0 == 'a` to be added as
967
+ /// a constraint, and thus ensures that they are in the same SCC.
968
+ ///
969
+ /// So why can't we do a more correct routine? Well, we could
970
+ /// *almost* use the `relate_tys` code, but the way it is
971
+ /// currently setup it creates inference variables to deal with
972
+ /// higher-ranked things and so forth, and right now the inference
973
+ /// context is not permitted to make more inference variables. So
974
+ /// we use this kind of hacky solution.
975
+ fn normalize_to_scc_representatives < T > ( & self , tcx : TyCtxt < ' _ , ' _ , ' tcx > , value : T ) -> T
976
+ where
977
+ T : TypeFoldable < ' tcx > ,
978
+ {
979
+ tcx. fold_regions ( & value, & mut false , |r, _db| {
980
+ let vid = self . to_region_vid ( r) ;
981
+ let scc = self . constraint_sccs . scc ( vid) ;
982
+ let repr = self . scc_representatives [ scc] ;
983
+ tcx. mk_region ( ty:: ReVar ( repr) )
984
+ } )
985
+ }
986
+
883
987
// Evaluate whether `sup_region: sub_region @ point`.
884
988
fn eval_outlives (
885
989
& self ,
0 commit comments