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