@@ -14,6 +14,7 @@ use rustc_index::IndexVec;
14
14
use rustc_infer:: infer:: NllRegionVariableOrigin ;
15
15
use rustc_infer:: infer:: region_constraints:: { GenericKind , VarInfos , VerifyBound } ;
16
16
use rustc_infer:: infer:: relate:: TypeRelation ;
17
+ use rustc_middle:: bug;
17
18
use rustc_middle:: ty:: relate:: { self , Relate , RelateResult } ;
18
19
use rustc_middle:: ty:: { self , Region , RegionVid , Ty , TyCtxt , UniverseIndex } ;
19
20
use rustc_span:: Span ;
@@ -30,6 +31,8 @@ use crate::ty::VarianceDiagInfo;
30
31
use crate :: type_check:: Locations ;
31
32
use crate :: universal_regions:: UniversalRegions ;
32
33
34
+ /// A set of outlives constraints after rewriting to remove
35
+ /// higher-kinded constraints.
33
36
pub ( crate ) struct LoweredConstraints < ' tcx > {
34
37
pub ( crate ) type_tests : Vec < LoweredTypeTest < ' tcx > > ,
35
38
pub ( crate ) sccs : Sccs < RegionVid , ConstraintSccIndex > ,
@@ -66,6 +69,7 @@ enum PlaceholderReachability {
66
69
max_placeholder : RegionVid ,
67
70
} ,
68
71
}
72
+
69
73
impl PlaceholderReachability {
70
74
fn merge ( self , other : PlaceholderReachability ) -> PlaceholderReachability {
71
75
use PlaceholderReachability :: * ;
@@ -101,7 +105,8 @@ impl PlaceholderReachability {
101
105
}
102
106
103
107
/// An annotation for region graph SCCs that tracks
104
- /// the values of its elements.
108
+ /// the values of its elements and properties of
109
+ /// SCCs reached from them.
105
110
#[ derive( Copy , Debug , Clone ) ]
106
111
struct RegionTracker {
107
112
/// The representative Region Variable Id for this SCC.
@@ -113,7 +118,13 @@ struct RegionTracker {
113
118
// Metadata about reachable placeholders
114
119
reachable_placeholders : PlaceholderReachability ,
115
120
116
- // Track the existential with the smallest universe we reach.
121
+ /// Track the existential with the smallest universe we reach.
122
+ /// For existentials, the assigned universe corresponds to the
123
+ /// largest universed placeholder they are allowed to end up in.
124
+ ///
125
+ /// In other words, this tracks the smallest maximum (hardest constraint)
126
+ /// of any existential this SCC reaches, and the rvid of the existential
127
+ /// that brought it.
117
128
min_universe_reachable_existential : Option < ( UniverseIndex , RegionVid ) > ,
118
129
}
119
130
@@ -148,8 +159,8 @@ impl scc::Annotation for RegionTracker {
148
159
// illegally reached universes, but they are not equally good as blame candidates.
149
160
// In general, the ones with the smallest indices of their RegionVids will
150
161
// be the best ones, and those will also be visited first. This code
151
- // then will suptly prefer a universe violation caused by a placeholder
152
- // with a small RegionVid over one with a large RegionVid .
162
+ // then will suptly prefer a universe violation happening close from where the
163
+ // constraint graph walk started over one that happens later .
153
164
// FIXME: a potential optimisation if this is slow is to reimplement
154
165
// this check as a boolean fuse, since it will idempotently turn
155
166
// true once triggered and never go false again.
@@ -164,10 +175,14 @@ impl scc::Annotation for RegionTracker {
164
175
}
165
176
}
166
177
178
+ /// Select the worst universe-constrained of two existentials.
167
179
fn smallest_reachable_existential (
168
180
min_universe_reachable_existential_1 : Option < ( UniverseIndex , RegionVid ) > ,
169
181
min_universe_reachable_existential_2 : Option < ( UniverseIndex , RegionVid ) > ,
170
182
) -> Option < ( UniverseIndex , RegionVid ) > {
183
+ // Note: this will prefer a small region vid over a large one. That's generally
184
+ // good, but this probably does not affect the outcome. It might affect diagnostics
185
+ // in the future.
171
186
match ( min_universe_reachable_existential_1, min_universe_reachable_existential_2) {
172
187
( Some ( a) , Some ( b) ) => Some ( std:: cmp:: min ( a, b) ) ,
173
188
( a, b) => a. or ( b) ,
@@ -307,6 +322,17 @@ impl scc::Annotations<RegionVid, ConstraintSccIndex, Representative>
307
322
}
308
323
}
309
324
325
+ /// Identify errors where placeholders illegally reach other regions, and generate
326
+ /// errors stored into `errors_buffer`.
327
+ ///
328
+ /// There are two sources of such errors:
329
+ /// 1. A placeholder reaches (possibly transitively) another placeholder.
330
+ /// 2. A placeholder `p` reaches (possibly transitively) an existential `e`,
331
+ /// where `e` has an allowed maximum universe smaller than `p`'s.
332
+ ///
333
+ /// There are other potential placeholder errors, but those are detected after
334
+ /// region inference, since it may apply type tests or member constraints that
335
+ /// alter the contents of SCCs and thus can't be detected at this point.
310
336
#[ instrument( skip( definitions, sccs, annotations, errors_buffer) , level = "debug" ) ]
311
337
fn find_placeholder_mismatch_errors < ' tcx > (
312
338
definitions : & IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
@@ -395,8 +421,7 @@ fn find_placeholder_mismatch_errors<'tcx>(
395
421
///
396
422
/// This code is a stop-gap measure in preparation for the future trait solver.
397
423
///
398
- /// Every constraint added by this method is an
399
- /// internal `IllegalUniverse` constraint.
424
+ /// Every constraint added by this method is an internal `IllegalUniverse` constraint.
400
425
#[ instrument( skip( tcx, outlives_constraints) ) ]
401
426
pub ( crate ) fn rewrite_higher_kinded_outlives_as_constraints < ' tcx > (
402
427
mut outlives_constraints : OutlivesConstraintSet < ' tcx > ,
@@ -501,12 +526,17 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
501
526
scc_annotations[ sccs. scc ( r1) ] . min_universe ( ) != scc_annotations[ sccs. scc ( r2) ] . min_universe ( )
502
527
} ;
503
528
529
+ // Rewrite member constraints to exclude choices of regions that would violate
530
+ // the respective region's computed (minimum) universe.
504
531
let member_constraints = member_constraints. into_mapped (
505
532
|r| sccs. scc ( r) ,
506
533
|r| scc_annotations[ sccs. scc ( r) ] . in_root_universe ( ) ,
507
534
different_universes,
508
535
) ;
509
536
537
+ // We strip out the extra information and only keep the `Representative`;
538
+ // all the information about placeholders and their universes is no longer
539
+ // needed.
510
540
let scc_representatives = scc_annotations
511
541
. into_iter ( )
512
542
. map ( |rich_annotation| rich_annotation. into_representative ( ) )
@@ -529,13 +559,16 @@ fn rewrite_outlives<'tcx>(
529
559
outlives_constraints : & mut OutlivesConstraintSet < ' tcx > ,
530
560
definitions : & IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
531
561
) -> FxHashSet < ConstraintSccIndex > {
532
- // Is this SCC already outliving static directly or transitively?
562
+ // Is this SCC already outliving ' static directly or transitively?
533
563
let mut outlives_static = FxHashSet :: default ( ) ;
534
564
535
565
let mut memoised_constraint_graph: Option < ConstraintGraph < Normal > > = None ;
536
566
537
567
for scc in sccs. all_sccs ( ) {
538
568
let annotation: RegionTracker = annotations. scc_to_annotation [ scc] ;
569
+ // you may be tempted to add 'static to `outlives_static`, but
570
+ // we need it to be empty if no constraints were added for a
571
+ // later cheap check to see if we did any work.
539
572
if scc == sccs. scc ( fr_static) {
540
573
trace ! ( "Skipping adding 'static: 'static." ) ;
541
574
// No use adding 'static: 'static.
@@ -631,7 +664,10 @@ fn find_region<'tcx>(
631
664
}
632
665
}
633
666
}
634
- unreachable ! ( "Should have found something!" ) ;
667
+ // since this function is used exclusively in this module, we know
668
+ // we are only searching for regions we found in the region graph,
669
+ // so if we don't find what we are looking for there's a bug somwehere.
670
+ bug ! ( "Should have found something!" ) ;
635
671
}
636
672
637
673
#[ derive( Debug , Clone ) ]
@@ -647,6 +683,7 @@ pub(crate) enum RewrittenVerifyBound<'tcx> {
647
683
Unsatisfied ,
648
684
}
649
685
686
+ /// A type test rewritten to handle higher-kinded concerns.
650
687
#[ derive( Debug , Clone ) ]
651
688
pub ( crate ) enum LoweredTypeTest < ' tcx > {
652
689
Untouched ( TypeTest < ' tcx > ) ,
@@ -682,6 +719,8 @@ fn rewrite_verify_bound<'t>(
682
719
// are both empty. This bit ensures that whatever comes out of the
683
720
// bound also matches the placeholder reachability of the lower bound.
684
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.
685
724
let mut m = MatchUniverses :: new ( tcx, sccs, scc_annotations, universal_regions) ;
686
725
let verify_if_eq = verify_if_eq_b. skip_binder ( ) ;
687
726
let what_error = m. relate ( verify_if_eq. ty , generic_kind. to_ty ( tcx) ) ;
@@ -731,43 +770,60 @@ fn rewrite_verify_bound<'t>(
731
770
Either :: Right ( RewrittenVerifyBound :: Unsatisfied )
732
771
}
733
772
}
734
- // Note that this (and below) claims the contents are always rewritten, even if they weren't.
735
- // This does not affect correctness, but is surprising.
736
- VerifyBound :: AnyBound ( verify_bounds) => Either :: Right ( RewrittenVerifyBound :: AnyBound (
737
- verify_bounds
738
- . into_iter ( )
739
- . map ( |bound| {
740
- rewrite_verify_bound (
741
- bound,
742
- lower_scc,
743
- sccs,
744
- scc_annotations,
745
- universal_regions,
746
- tcx,
747
- generic_kind,
748
- )
749
- } )
750
- . collect ( ) ,
751
- ) ) ,
752
- VerifyBound :: AllBounds ( verify_bounds) => Either :: Right ( RewrittenVerifyBound :: AllBounds (
753
- verify_bounds
754
- . into_iter ( )
755
- . map ( |bound| {
756
- rewrite_verify_bound (
757
- bound,
758
- lower_scc,
759
- sccs,
760
- scc_annotations,
761
- universal_regions,
762
- tcx,
763
- generic_kind,
764
- )
765
- } )
766
- . collect ( ) ,
767
- ) ) ,
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
+ ) ) )
797
+ }
768
798
}
769
799
}
770
800
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 ( )
825
+ }
826
+
771
827
impl < ' t > TypeTest < ' t > {
772
828
#[ instrument( skip( sccs, tcx, universal_regions, scc_annotations) , ret) ]
773
829
fn rewrite_higher_kinded_constraints (
@@ -873,6 +929,7 @@ impl<'tcx, 'v> TypeRelation<TyCtxt<'tcx>> for MatchUniverses<'tcx, 'v> {
873
929
}
874
930
}
875
931
932
+ /// A `TypeRelation` visitor that computes the largest universe.
876
933
struct MatchUniverses < ' tcx , ' v > {
877
934
tcx : TyCtxt < ' tcx > ,
878
935
pattern_depth : ty:: DebruijnIndex ,
0 commit comments