@@ -13,12 +13,12 @@ use rustc_infer::infer::RegionVariableOrigin;
13
13
use rustc_middle:: bug;
14
14
use rustc_middle:: mir:: ConstraintCategory ;
15
15
use rustc_middle:: ty:: { RegionVid , UniverseIndex } ;
16
- use tracing:: { debug, trace} ;
16
+ use tracing:: { debug, instrument , trace} ;
17
17
18
18
use crate :: constraints:: graph:: { ConstraintGraph , Normal , RegionGraph } ;
19
19
use crate :: constraints:: { ConstraintSccIndex , OutlivesConstraintSet } ;
20
20
use crate :: consumers:: OutlivesConstraint ;
21
- use crate :: diagnostics:: UniverseInfo ;
21
+ use crate :: diagnostics:: { RegionErrorKind , RegionErrors , UniverseInfo } ;
22
22
use crate :: member_constraints:: MemberConstraintSet ;
23
23
use crate :: region_infer:: values:: { LivenessValues , PlaceholderIndices } ;
24
24
use crate :: region_infer:: { ConstraintSccs , RegionDefinition , Representative , TypeTest } ;
@@ -181,6 +181,43 @@ impl RegionTracker {
181
181
182
182
Some ( ( max_u_rvid, max_u) )
183
183
}
184
+
185
+ /// Check for the second and final type of placeholder leak,
186
+ /// where a placeholder `'p` outlives (transitively) an existential `'e`
187
+ /// and `'e` cannot name `'p`. This is sort of a dual of `unnameable_placeholder`;
188
+ /// one of the members of this SCC cannot be named by the SCC.
189
+ ///
190
+ /// Returns *a* culprit (though there may be more than one).
191
+ fn reaches_existential_that_cannot_name_us ( & self ) -> Option < RegionVid > {
192
+ let Representative :: Placeholder ( _p) = self . representative else {
193
+ return None ;
194
+ } ;
195
+
196
+ let ( reachable_lowest_max_u, reachable_lowest_max_u_rvid) = self . max_nameable_universe ;
197
+
198
+ ( !self . reachable_placeholders . can_be_named_by ( reachable_lowest_max_u) )
199
+ . then_some ( reachable_lowest_max_u_rvid)
200
+ }
201
+
202
+ /// Determine if this SCC reaches a placeholder that isn't `placeholder_rvid`,
203
+ /// returning it if that is the case. This prefers the placeholder with the
204
+ /// smallest region variable ID.
205
+ fn reaches_other_placeholder ( & self , placeholder_rvid : RegionVid ) -> Option < RegionVid > {
206
+ match self . reachable_placeholders {
207
+ PlaceholderReachability :: NoPlaceholders => None ,
208
+ PlaceholderReachability :: Placeholders { min_placeholder, max_placeholder, .. }
209
+ if min_placeholder == max_placeholder =>
210
+ {
211
+ None
212
+ }
213
+ PlaceholderReachability :: Placeholders { min_placeholder, max_placeholder, .. }
214
+ if min_placeholder == placeholder_rvid =>
215
+ {
216
+ Some ( max_placeholder)
217
+ }
218
+ PlaceholderReachability :: Placeholders { min_placeholder, .. } => Some ( min_placeholder) ,
219
+ }
220
+ }
184
221
}
185
222
/// Pick the smallest universe index out of two, preferring
186
223
/// the first argument if they are equal.
@@ -293,6 +330,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
293
330
constraints : MirTypeckRegionConstraints < ' tcx > ,
294
331
universal_region_relations : & Frozen < UniversalRegionRelations < ' tcx > > ,
295
332
infcx : & BorrowckInferCtxt < ' tcx > ,
333
+ errors_buffer : & mut RegionErrors < ' tcx > ,
296
334
) -> LoweredConstraints < ' tcx > {
297
335
let universal_regions = & universal_region_relations. universal_regions ;
298
336
let ( definitions, has_placeholders) = region_definitions ( universal_regions, infcx) ;
@@ -359,6 +397,13 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
359
397
& definitions,
360
398
) ;
361
399
400
+ find_placeholder_mismatch_errors (
401
+ & definitions,
402
+ & constraint_sccs,
403
+ & scc_annotations,
404
+ errors_buffer,
405
+ ) ;
406
+
362
407
let ( constraint_sccs, scc_annotations) = if added_constraints {
363
408
let mut annotations = SccAnnotations :: init ( & definitions) ;
364
409
@@ -510,3 +555,65 @@ fn find_region<'tcx>(
510
555
// so if we don't find what we are looking for there's a bug somwehere.
511
556
bug ! ( "Should have found something!" ) ;
512
557
}
558
+
559
+ /// Identify errors where placeholders illegally reach other regions, and generate
560
+ /// errors stored into `errors_buffer`.
561
+ ///
562
+ /// There are two sources of such errors:
563
+ /// 1. A placeholder reaches (possibly transitively) another placeholder.
564
+ /// 2. A placeholder `p` reaches (possibly transitively) an existential `e`,
565
+ /// where `e` has an allowed maximum universe smaller than `p`'s.
566
+ ///
567
+ /// There are other potential placeholder errors, but those are detected after
568
+ /// region inference, since it may apply type tests or member constraints that
569
+ /// alter the contents of SCCs and thus can't be detected at this point.
570
+ #[ instrument( skip( definitions, sccs, annotations, errors_buffer) , level = "debug" ) ]
571
+ fn find_placeholder_mismatch_errors < ' tcx > (
572
+ definitions : & IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
573
+ sccs : & Sccs < RegionVid , ConstraintSccIndex > ,
574
+ annotations : & SccAnnotations < ' _ , ' _ , RegionTracker > ,
575
+ errors_buffer : & mut RegionErrors < ' tcx > ,
576
+ ) {
577
+ use NllRegionVariableOrigin :: Placeholder ;
578
+ for ( rvid, definition) in definitions. iter_enumerated ( ) {
579
+ let Placeholder ( origin_a) = definition. origin else {
580
+ continue ;
581
+ } ;
582
+
583
+ let scc = sccs. scc ( rvid) ;
584
+ let annotation = annotations. scc_to_annotation [ scc] ;
585
+
586
+ if let Some ( existental_that_cannot_name_rvid) =
587
+ annotation. reaches_existential_that_cannot_name_us ( )
588
+ {
589
+ errors_buffer. push ( RegionErrorKind :: PlaceholderOutlivesExistentialThatCannotNameIt {
590
+ longer_fr : rvid,
591
+ existental_that_cannot_name_longer : existental_that_cannot_name_rvid,
592
+ placeholder : origin_a,
593
+ } )
594
+ }
595
+
596
+ let Some ( other_placeholder) = annotation. reaches_other_placeholder ( rvid) else {
597
+ trace ! ( "{rvid:?} reaches no other placeholders" ) ;
598
+ continue ;
599
+ } ;
600
+
601
+ debug ! (
602
+ "Placeholder {rvid:?} of SCC {scc:?} reaches other placeholder {other_placeholder:?}"
603
+ ) ;
604
+
605
+ // FIXME SURELY there is a neater way to do this?
606
+ let Placeholder ( origin_b) = definitions[ other_placeholder] . origin else {
607
+ unreachable ! (
608
+ "Region {rvid:?}, {other_placeholder:?} should be placeholders but aren't!"
609
+ ) ;
610
+ } ;
611
+
612
+ errors_buffer. push ( RegionErrorKind :: PlaceholderOutlivesPlaceholder {
613
+ rvid_a : rvid,
614
+ rvid_b : other_placeholder,
615
+ origin_a,
616
+ origin_b,
617
+ } ) ;
618
+ }
619
+ }
0 commit comments