@@ -47,6 +47,14 @@ pub(crate) mod values;
47
47
48
48
pub ( crate ) type ConstraintSccs = Sccs < RegionVid , ConstraintSccIndex , RegionTracker > ;
49
49
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
+ }
50
58
/// An annotation for region graph SCCs that tracks
51
59
/// the values of its elements.
52
60
#[ derive( Copy , Debug , Clone ) ]
@@ -63,71 +71,127 @@ pub struct RegionTracker {
63
71
/// it's the one with the smallest Region Variable ID.
64
72
pub ( crate ) representative : RegionVid ,
65
73
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 > ,
68
82
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 ,
71
85
}
72
86
73
87
impl 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 :: * ;
80
90
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 )
83
92
{
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
89
104
}
90
105
91
106
fn merge_reached ( mut self , other : Self ) -> Self {
92
- // No update to in-component values, only add seen values.
93
107
self . merge_min_max_seen ( & other) ;
94
108
self
95
109
}
96
110
}
97
111
98
112
impl RegionTracker {
99
113
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 ,
105
120
} ;
106
121
122
+ let rvid_is_placeholder = representative_origin == Placeholder ;
123
+
107
124
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 } ;
109
128
110
129
Self {
111
130
max_placeholder_universe_reached : placeholder_universe,
112
131
min_reachable_universe : definition. universe ,
113
132
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,
116
137
}
117
138
}
118
139
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
+
119
158
/// If the representative is a placeholder, return it,
120
159
/// otherwise return None.
121
160
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
+ }
123
166
}
124
167
125
168
/// The smallest-indexed universe reachable from and/or in this SCC.
126
169
fn min_universe ( self ) -> UniverseIndex {
127
170
self . min_reachable_universe
128
171
}
129
172
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
+
130
192
fn merge_min_max_seen ( & mut self , other : & Self ) {
193
+ self . merge_reachable_placeholders ( other) ;
194
+
131
195
self . max_placeholder_universe_reached = std:: cmp:: max (
132
196
self . max_placeholder_universe_reached ,
133
197
other. max_placeholder_universe_reached ,
@@ -137,10 +201,12 @@ impl RegionTracker {
137
201
std:: cmp:: min ( self . min_reachable_universe , other. min_reachable_universe ) ;
138
202
}
139
203
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.
142
207
pub ( crate ) fn has_incompatible_universes ( & self ) -> bool {
143
208
self . min_universe ( ) . cannot_name ( self . max_placeholder_universe_reached )
209
+ || self . placeholder_reaches_placeholder ( )
144
210
}
145
211
}
146
212
@@ -412,7 +478,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
412
478
member_constraints_in : MemberConstraintSet < ' tcx , RegionVid > ,
413
479
universe_causes : FxIndexMap < ty:: UniverseIndex , UniverseInfo < ' tcx > > ,
414
480
type_tests : Vec < TypeTest < ' tcx > > ,
415
- liveness_constraints : LivenessValues ,
481
+ mut liveness_constraints : LivenessValues ,
416
482
elements : & Rc < DenseLocationMap > ,
417
483
) -> Self {
418
484
debug ! ( "universal_regions: {:#?}" , universal_regions) ;
@@ -421,10 +487,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
421
487
debug ! ( "type tests: {:#?}" , type_tests) ;
422
488
423
489
// 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
+ } ;
428
503
429
504
let constraint_sccs =
430
505
outlives_constraints. add_outlives_static ( & universal_regions, & definitions) ;
@@ -445,7 +520,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
445
520
let member_constraints =
446
521
Rc :: new ( member_constraints_in. into_mapped ( |r| constraint_sccs. scc ( r) ) ) ;
447
522
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 {
449
540
var_infos,
450
541
definitions,
451
542
liveness_constraints,
@@ -460,99 +551,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
460
551
type_tests,
461
552
universal_regions,
462
553
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
- }
556
554
}
557
555
}
558
556
@@ -1638,12 +1636,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1638
1636
placeholder : ty:: PlaceholderRegion ,
1639
1637
errors_buffer : & mut RegionErrors < ' tcx > ,
1640
1638
) {
1641
- debug ! ( "check_bound_universal_region(fr={:?}, placeholder={:?})" , longer_fr, placeholder, ) ;
1639
+ debug ! ( "check_bound_universal_region(fr={:?}, placeholder={:?})" , longer_fr, placeholder) ;
1642
1640
1643
1641
let longer_fr_scc = self . constraint_sccs . scc ( longer_fr) ;
1644
1642
debug ! ( "check_bound_universal_region: longer_fr_scc={:?}" , longer_fr_scc, ) ;
1645
1643
1646
1644
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
+ ) ;
1647
1648
match error_element {
1648
1649
RegionElement :: Location ( _) | RegionElement :: RootUniversalRegion ( _) => { }
1649
1650
}
0 commit comments