@@ -46,6 +46,14 @@ pub(crate) mod values;
4646
4747pub ( crate ) type ConstraintSccs = Sccs < RegionVid , ConstraintSccIndex , RegionTracker > ;
4848
49+ /// A simpler version of `RegionVariableOrigin` without the
50+ /// metadata.
51+ #[ derive( Copy , Debug , Clone , PartialEq ) ]
52+ enum RepresentativeOrigin {
53+ Existential ,
54+ Placeholder ,
55+ FreeRegion ,
56+ }
4957/// An annotation for region graph SCCs that tracks
5058/// the values of its elements.
5159#[ derive( Copy , Debug , Clone ) ]
@@ -62,71 +70,127 @@ pub struct RegionTracker {
6270 /// it's the one with the smallest Region Variable ID.
6371 pub ( crate ) representative : RegionVid ,
6472
65- /// Is the current representative a placeholder?
66- representative_is_placeholder : bool ,
73+ /// Where does the representative region variable come from?
74+ representative_origin : RepresentativeOrigin ,
75+
76+ /// The smallest reachable placeholder from this SCC (including in it).
77+ min_reachable_placeholder : Option < RegionVid > ,
78+
79+ /// The largest reachable placeholder from this SCC (including in it).
80+ max_reachable_placeholder : Option < RegionVid > ,
6781
68- /// Is the current representative existentially quantified ?
69- representative_is_existential : bool ,
82+ /// Is there at least one placeholder in this SCC ?
83+ contains_placeholder : bool ,
7084}
7185
7286impl scc:: Annotation for RegionTracker {
73- fn merge_scc ( mut self , mut other : Self ) -> Self {
74- // Prefer any placeholder over any existential
75- if other. representative_is_placeholder && self . representative_is_existential {
76- other. merge_min_max_seen ( & self ) ;
77- return other;
78- }
87+ fn merge_scc ( self , other : Self ) -> Self {
88+ use RepresentativeOrigin :: * ;
7989
80- if self . representative_is_placeholder && other. representative_is_existential
81- || ( self . representative <= other. representative )
90+ let ( mut shorter, longer) = match ( self . representative_origin , other. representative_origin )
8291 {
83- self . merge_min_max_seen ( & other) ;
84- return self ;
85- }
86- other. merge_min_max_seen ( & self ) ;
87- other
92+ // Prefer any placeholder over any existential
93+ ( Existential , Placeholder ) => ( other, self ) ,
94+ ( Placeholder , Existential ) => ( self , other) ,
95+
96+ // In any other case, pick the one with the smallest id.
97+ _ if self . representative <= other. representative => ( self , other) ,
98+ _ => ( other, self ) ,
99+ } ;
100+ shorter. contains_placeholder |= longer. contains_placeholder ;
101+ shorter. merge_min_max_seen ( & longer) ;
102+ shorter
88103 }
89104
90105 fn merge_reached ( mut self , other : Self ) -> Self {
91- // No update to in-component values, only add seen values.
92106 self . merge_min_max_seen ( & other) ;
93107 self
94108 }
95109}
96110
97111impl RegionTracker {
98112 pub ( crate ) fn new ( rvid : RegionVid , definition : & RegionDefinition < ' _ > ) -> Self {
99- let ( representative_is_placeholder, representative_is_existential) = match definition. origin
100- {
101- rustc_infer:: infer:: NllRegionVariableOrigin :: FreeRegion => ( false , false ) ,
102- rustc_infer:: infer:: NllRegionVariableOrigin :: Placeholder ( _) => ( true , false ) ,
103- rustc_infer:: infer:: NllRegionVariableOrigin :: Existential { .. } => ( false , true ) ,
113+ use RepresentativeOrigin :: * ;
114+
115+ let representative_origin = match definition. origin {
116+ NllRegionVariableOrigin :: FreeRegion => FreeRegion ,
117+ NllRegionVariableOrigin :: Placeholder ( _) => Placeholder ,
118+ NllRegionVariableOrigin :: Existential { .. } => Existential ,
104119 } ;
105120
121+ let rvid_is_placeholder = representative_origin == Placeholder ;
122+
106123 let placeholder_universe =
107- if representative_is_placeholder { definition. universe } else { UniverseIndex :: ROOT } ;
124+ if rvid_is_placeholder { definition. universe } else { UniverseIndex :: ROOT } ;
125+
126+ let representative_if_placeholder = if rvid_is_placeholder { Some ( rvid) } else { None } ;
108127
109128 Self {
110129 max_placeholder_universe_reached : placeholder_universe,
111130 min_reachable_universe : definition. universe ,
112131 representative : rvid,
113- representative_is_placeholder,
114- representative_is_existential,
132+ representative_origin,
133+ min_reachable_placeholder : representative_if_placeholder,
134+ max_reachable_placeholder : representative_if_placeholder,
135+ contains_placeholder : rvid_is_placeholder,
115136 }
116137 }
117138
139+ /// Return true if this SCC contains a placeholder that
140+ /// reaches another placeholder, through other SCCs or within
141+ /// it.
142+ fn placeholder_reaches_placeholder ( & self ) -> bool {
143+ // If min and max are different then at least two placeholders
144+ // must be reachable from us. It remains to determine if and
145+ // whose problem that is.
146+ //
147+ // If we are not a placeholder
148+ // we are seeing upstream placeholders, which may be fine, or
149+ // if it is a problem it's the problem for other placeholders.
150+ //
151+ // If we *are* a placeholder, we are reaching at least one other
152+ // placeholder upstream.
153+ self . contains_placeholder
154+ && self . min_reachable_placeholder != self . max_reachable_placeholder
155+ }
156+
118157 /// If the representative is a placeholder, return it,
119158 /// otherwise return None.
120159 fn placeholder_representative ( & self ) -> Option < RegionVid > {
121- if self . representative_is_placeholder { Some ( self . representative ) } else { None }
160+ if self . representative_origin == RepresentativeOrigin :: Placeholder {
161+ Some ( self . representative )
162+ } else {
163+ None
164+ }
122165 }
123166
124167 /// The smallest-indexed universe reachable from and/or in this SCC.
125168 fn min_universe ( self ) -> UniverseIndex {
126169 self . min_reachable_universe
127170 }
128171
172+ fn merge_reachable_placeholders ( & mut self , other : & Self ) {
173+ // The largest reachable placeholder, or None if neither reaches any.
174+ // This works because None is smaller than any Some.
175+ let max_max = self . max_reachable_placeholder . max ( other. max_reachable_placeholder ) ;
176+
177+ // Neither reach a placeholder
178+ if max_max. is_none ( ) {
179+ return ;
180+ }
181+
182+ self . max_reachable_placeholder = max_max;
183+
184+ // If the smallest one is None, pick the largest Option; the single Some.
185+ self . min_reachable_placeholder = self
186+ . min_reachable_placeholder
187+ . min ( other. min_reachable_placeholder )
188+ . or_else ( || self . min_reachable_placeholder . max ( other. min_reachable_placeholder ) ) ;
189+ }
190+
129191 fn merge_min_max_seen ( & mut self , other : & Self ) {
192+ self . merge_reachable_placeholders ( other) ;
193+
130194 self . max_placeholder_universe_reached = std:: cmp:: max (
131195 self . max_placeholder_universe_reached ,
132196 other. max_placeholder_universe_reached ,
@@ -136,10 +200,12 @@ impl RegionTracker {
136200 std:: cmp:: min ( self . min_reachable_universe , other. min_reachable_universe ) ;
137201 }
138202
139- /// Returns `true` if during the annotated SCC reaches a placeholder
140- /// with a universe larger than the smallest reachable one, `false` otherwise.
203+ /// Returns `true` if the annotated SCC reaches a placeholder
204+ /// with a universe larger than the smallest reachable one,
205+ /// or if a placeholder reaches another placeholder, `false` otherwise.
141206 pub ( crate ) fn has_incompatible_universes ( & self ) -> bool {
142207 self . min_universe ( ) . cannot_name ( self . max_placeholder_universe_reached )
208+ || self . placeholder_reaches_placeholder ( )
143209 }
144210}
145211
@@ -411,7 +477,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
411477 member_constraints_in : MemberConstraintSet < ' tcx , RegionVid > ,
412478 universe_causes : FxIndexMap < ty:: UniverseIndex , UniverseInfo < ' tcx > > ,
413479 type_tests : Vec < TypeTest < ' tcx > > ,
414- liveness_constraints : LivenessValues ,
480+ mut liveness_constraints : LivenessValues ,
415481 elements : & Rc < DenseLocationMap > ,
416482 ) -> Self {
417483 debug ! ( "universal_regions: {:#?}" , universal_regions) ;
@@ -420,10 +486,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
420486 debug ! ( "type tests: {:#?}" , type_tests) ;
421487
422488 // Create a RegionDefinition for each inference variable.
423- let definitions: IndexVec < _ , _ > = var_infos
424- . iter ( )
425- . map ( |info| RegionDefinition :: new ( info. universe , info. origin ) )
426- . collect ( ) ;
489+ let definitions = {
490+ let mut definitions: IndexVec < _ , _ > = var_infos
491+ . iter ( )
492+ . map ( |info| RegionDefinition :: new ( info. universe , info. origin ) )
493+ . collect ( ) ;
494+
495+ // Add external names from universal regions in fun function definitions.
496+ for ( external_name, variable) in universal_regions. named_universal_regions ( ) {
497+ debug ! ( "region {:?} has external name {:?}" , variable, external_name) ;
498+ definitions[ variable] . external_name = Some ( external_name) ;
499+ }
500+ definitions
501+ } ;
427502
428503 let constraint_sccs =
429504 outlives_constraints. add_outlives_static ( & universal_regions, & definitions) ;
@@ -444,7 +519,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
444519 let member_constraints =
445520 Rc :: new ( member_constraints_in. into_mapped ( |r| constraint_sccs. scc ( r) ) ) ;
446521
447- let mut result = Self {
522+ // Initialise free, universally quantified regions to be live at all points.
523+ for variable in definitions. indices ( ) {
524+ if let NllRegionVariableOrigin :: FreeRegion = definitions[ variable] . origin {
525+ // For each free, universally quantified region X:
526+
527+ let scc = constraint_sccs. scc ( variable) ;
528+
529+ // Add all nodes in the CFG to liveness constraints
530+ liveness_constraints. add_all_points ( variable) ;
531+ scc_values. add_all_points ( scc) ;
532+
533+ // Add `end(X)` into the set for X.
534+ scc_values. add_element ( scc, variable) ;
535+ }
536+ }
537+
538+ Self {
448539 var_infos,
449540 definitions,
450541 liveness_constraints,
@@ -459,99 +550,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
459550 type_tests,
460551 universal_regions,
461552 universal_region_relations,
462- } ;
463-
464- result. init_free_and_bound_regions ( ) ;
465-
466- result
467- }
468-
469- /// Initializes the region variables for each universally
470- /// quantified region (lifetime parameter). The first N variables
471- /// always correspond to the regions appearing in the function
472- /// signature (both named and anonymous) and where-clauses. This
473- /// function iterates over those regions and initializes them with
474- /// minimum values.
475- ///
476- /// For example:
477- /// ```
478- /// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ }
479- /// ```
480- /// would initialize two variables like so:
481- /// ```ignore (illustrative)
482- /// R0 = { CFG, R0 } // 'a
483- /// R1 = { CFG, R0, R1 } // 'b
484- /// ```
485- /// Here, R0 represents `'a`, and it contains (a) the entire CFG
486- /// and (b) any universally quantified regions that it outlives,
487- /// which in this case is just itself. R1 (`'b`) in contrast also
488- /// outlives `'a` and hence contains R0 and R1.
489- ///
490- /// This bit of logic also handles invalid universe relations
491- /// for higher-kinded types.
492- ///
493- /// We Walk each SCC `A` and `B` such that `A: B`
494- /// and ensure that universe(A) can see universe(B).
495- ///
496- /// This serves to enforce the 'empty/placeholder' hierarchy
497- /// (described in more detail on `RegionKind`):
498- ///
499- /// ```ignore (illustrative)
500- /// static -----+
501- /// | |
502- /// empty(U0) placeholder(U1)
503- /// | /
504- /// empty(U1)
505- /// ```
506- ///
507- /// In particular, imagine we have variables R0 in U0 and R1
508- /// created in U1, and constraints like this;
509- ///
510- /// ```ignore (illustrative)
511- /// R1: !1 // R1 outlives the placeholder in U1
512- /// R1: R0 // R1 outlives R0
513- /// ```
514- ///
515- /// Here, we wish for R1 to be `'static`, because it
516- /// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
517- ///
518- /// Thanks to this loop, what happens is that the `R1: R0`
519- /// constraint has lowered the universe of `R1` to `U0`, which in turn
520- /// means that the `R1: !1` constraint here will cause
521- /// `R1` to become `'static`.
522- fn init_free_and_bound_regions ( & mut self ) {
523- // Update the names (if any)
524- // This iterator has unstable order but we collect it all into an IndexVec
525- for ( external_name, variable) in self . universal_regions . named_universal_regions ( ) {
526- debug ! (
527- "init_free_and_bound_regions: region {:?} has external name {:?}" ,
528- variable, external_name
529- ) ;
530- self . definitions [ variable] . external_name = Some ( external_name) ;
531- }
532-
533- for variable in self . definitions . indices ( ) {
534- let scc = self . constraint_sccs . scc ( variable) ;
535-
536- match self . definitions [ variable] . origin {
537- NllRegionVariableOrigin :: FreeRegion => {
538- // For each free, universally quantified region X:
539-
540- // Add all nodes in the CFG to liveness constraints
541- self . liveness_constraints . add_all_points ( variable) ;
542- self . scc_values . add_all_points ( scc) ;
543-
544- // Add `end(X)` into the set for X.
545- self . scc_values . add_element ( scc, variable) ;
546- }
547-
548- NllRegionVariableOrigin :: Placeholder { .. } => {
549- // Placeholders are already handled by rewriting constraints.
550- }
551- NllRegionVariableOrigin :: Existential { .. } => {
552- // For existential, regions, nothing to do.
553- }
554- }
555553 }
556554 }
557555
@@ -1637,12 +1635,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16371635 placeholder : ty:: PlaceholderRegion ,
16381636 errors_buffer : & mut RegionErrors < ' tcx > ,
16391637 ) {
1640- debug ! ( "check_bound_universal_region(fr={:?}, placeholder={:?})" , longer_fr, placeholder, ) ;
1638+ debug ! ( "check_bound_universal_region(fr={:?}, placeholder={:?})" , longer_fr, placeholder) ;
16411639
16421640 let longer_fr_scc = self . constraint_sccs . scc ( longer_fr) ;
16431641 debug ! ( "check_bound_universal_region: longer_fr_scc={:?}" , longer_fr_scc, ) ;
16441642
16451643 for error_element in self . scc_values . elements_contained_in ( longer_fr_scc) {
1644+ debug ! (
1645+ "check_bound_universal_region, error_element: {error_element:?} for placeholder {placeholder:?} in scc: {longer_fr_scc:?}"
1646+ ) ;
16461647 match error_element {
16471648 RegionElement :: Location ( _) | RegionElement :: RootUniversalRegion ( _) => { }
16481649 }
0 commit comments