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