@@ -13,12 +13,12 @@ use rustc_infer::infer::RegionVariableOrigin;
1313use rustc_middle:: bug;
1414use rustc_middle:: mir:: ConstraintCategory ;
1515use rustc_middle:: ty:: { RegionVid , UniverseIndex } ;
16- use tracing:: { debug, trace} ;
16+ use tracing:: { debug, instrument , trace} ;
1717
1818use crate :: constraints:: graph:: { ConstraintGraph , Normal , RegionGraph } ;
1919use crate :: constraints:: { ConstraintSccIndex , OutlivesConstraintSet } ;
2020use crate :: consumers:: OutlivesConstraint ;
21- use crate :: diagnostics:: UniverseInfo ;
21+ use crate :: diagnostics:: { RegionErrorKind , RegionErrors , UniverseInfo } ;
2222use crate :: member_constraints:: MemberConstraintSet ;
2323use crate :: region_infer:: values:: { LivenessValues , PlaceholderIndices } ;
2424use crate :: region_infer:: { ConstraintSccs , RegionDefinition , Representative , TypeTest } ;
@@ -181,6 +181,43 @@ impl RegionTracker {
181181
182182 Some ( ( max_u_rvid, max_u) )
183183 }
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+ }
184221}
185222/// Pick the smallest universe index out of two, preferring
186223/// the first argument if they are equal.
@@ -293,6 +330,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
293330 constraints : MirTypeckRegionConstraints < ' tcx > ,
294331 universal_region_relations : & Frozen < UniversalRegionRelations < ' tcx > > ,
295332 infcx : & BorrowckInferCtxt < ' tcx > ,
333+ errors_buffer : & mut RegionErrors < ' tcx > ,
296334) -> LoweredConstraints < ' tcx > {
297335 let universal_regions = & universal_region_relations. universal_regions ;
298336 let ( definitions, has_placeholders) = region_definitions ( universal_regions, infcx) ;
@@ -359,6 +397,13 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
359397 & definitions,
360398 ) ;
361399
400+ find_placeholder_mismatch_errors (
401+ & definitions,
402+ & constraint_sccs,
403+ & scc_annotations,
404+ errors_buffer,
405+ ) ;
406+
362407 let ( constraint_sccs, scc_annotations) = if added_constraints {
363408 let mut annotations = SccAnnotations :: init ( & definitions) ;
364409
@@ -510,3 +555,65 @@ fn find_region<'tcx>(
510555 // so if we don't find what we are looking for there's a bug somwehere.
511556 bug ! ( "Should have found something!" ) ;
512557}
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