11//! Logic for lowering higher-kinded outlives constraints
22//! (with placeholders and universes) and turn them into regular
33//! outlives constraints.
4+ use std:: cmp;
5+
46use rustc_data_structures:: frozen:: Frozen ;
57use rustc_data_structures:: fx:: FxIndexMap ;
68use rustc_data_structures:: graph:: scc;
@@ -63,7 +65,7 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
6365#[ derive( Copy , Debug , Clone , PartialEq , Eq ) ]
6466pub ( crate ) struct PlaceholderReachability {
6567 /// The largest-universed placeholder we can reach
66- max_universe : ( UniverseIndex , RegionVid ) ,
68+ max_universe : RegionWithUniverse ,
6769
6870 /// The placeholder with the smallest ID
6971 pub ( crate ) min_placeholder : RegionVid ,
@@ -83,6 +85,30 @@ impl PlaceholderReachability {
8385 }
8486}
8587
88+ /// A region with its universe, ordered fist by largest unverse, then
89+ /// by smallest region (reverse region id order).
90+ #[ derive( Copy , Debug , Clone , PartialEq , Eq ) ]
91+ struct RegionWithUniverse {
92+ u : UniverseIndex ,
93+ r : RegionVid ,
94+ }
95+
96+ impl Ord for RegionWithUniverse {
97+ fn cmp ( & self , other : & Self ) -> cmp:: Ordering {
98+ if self . u . cmp ( & other. u ) == cmp:: Ordering :: Equal {
99+ self . r . cmp ( & other. r ) . reverse ( )
100+ } else {
101+ self . u . cmp ( & other. u )
102+ }
103+ }
104+ }
105+
106+ impl PartialOrd for RegionWithUniverse {
107+ fn partial_cmp ( & self , other : & Self ) -> Option < cmp:: Ordering > {
108+ Some ( self . cmp ( other) )
109+ }
110+ }
111+
86112/// An annotation for region graph SCCs that tracks
87113/// the values of its elements. This annotates a single SCC.
88114#[ derive( Copy , Debug , Clone ) ]
@@ -93,11 +119,10 @@ pub(crate) struct RegionTracker {
93119 /// regions reachable from this SCC.
94120 min_max_nameable_universe : UniverseIndex ,
95121
96- /// Does this SCC contain a placeholder region?
97- is_placeholder : Option < ( UniverseIndex , RegionVid ) > ,
122+ /// The worst-nameable (highest univers'd) placeholder region in this SCC.
123+ is_placeholder : Option < RegionWithUniverse > ,
98124
99- /// The worst-nameable (max univers'd) existential region
100- /// we reach.
125+ /// The worst-naming (min univers'd) existential region we reach.
101126 worst_existential : Option < ( UniverseIndex , RegionVid ) > ,
102127
103128 /// The representative Region Variable Id for this SCC.
@@ -110,7 +135,7 @@ impl RegionTracker {
110135
111136 let min_max_nameable_universe = definition. universe ;
112137 let representative = Representative :: new ( rvid, definition) ;
113- let universe_and_rvid = ( definition. universe , rvid ) ;
138+ let universe_and_rvid = RegionWithUniverse { r : rvid , u : definition. universe } ;
114139
115140 match definition. origin {
116141 FreeRegion => Self {
@@ -135,7 +160,7 @@ impl RegionTracker {
135160 reachable_placeholders : None ,
136161 min_max_nameable_universe,
137162 is_placeholder : None ,
138- worst_existential : Some ( universe_and_rvid ) ,
163+ worst_existential : Some ( ( definition . universe , rvid ) ) ,
139164 representative,
140165 } ,
141166 }
@@ -150,7 +175,7 @@ impl RegionTracker {
150175 }
151176
152177 pub ( crate ) fn max_placeholder_universe_reached ( self ) -> UniverseIndex {
153- self . reachable_placeholders . map ( |p| p. max_universe . 0 ) . unwrap_or ( UniverseIndex :: ROOT )
178+ self . reachable_placeholders . map ( |p| p. max_universe . u ) . unwrap_or ( UniverseIndex :: ROOT )
154179 }
155180
156181 /// Determine if we can name all the placeholders in `other`.
@@ -166,29 +191,12 @@ impl RegionTracker {
166191 }
167192}
168193
169- #[ inline( always) ]
170- fn either_or_merge < T > ( a : Option < T > , b : Option < T > , merge : fn ( T , T ) -> T ) -> Option < T > {
171- match ( a, b) {
172- ( None , x) | ( x, None ) => x,
173- ( Some ( a) , Some ( b) ) => Some ( merge ( a, b) ) ,
174- }
175- }
176-
177194impl scc:: Annotation for RegionTracker {
178195 fn merge_scc ( self , other : Self ) -> Self {
179196 trace ! ( "{:?} << {:?}" , self . representative, other. representative) ;
180197 Self {
181198 representative : self . representative . min ( other. representative ) ,
182- is_placeholder : either_or_merge (
183- self . is_placeholder ,
184- other. is_placeholder ,
185- |ours, theirs| {
186- let ( u1, r1) = ours;
187- let ( u2, r2) = theirs;
188-
189- if u1 == u2 { ( u1, r1. min ( r2) ) } else { ours. min ( theirs) }
190- } ,
191- ) ,
199+ is_placeholder : self . is_placeholder . max ( other. is_placeholder ) ,
192200 ..self . merge_reached ( other)
193201 }
194202 }
@@ -203,11 +211,13 @@ impl scc::Annotation for RegionTracker {
203211 min_max_nameable_universe : self
204212 . min_max_nameable_universe
205213 . min ( other. min_max_nameable_universe ) ,
206- reachable_placeholders : either_or_merge (
214+ reachable_placeholders : match (
207215 self . reachable_placeholders ,
208216 other. reachable_placeholders ,
209- |ours, theirs| ours. merge ( theirs) ,
210- ) ,
217+ ) {
218+ ( None , x) | ( x, None ) => x,
219+ ( Some ( ours) , Some ( theirs) ) => Some ( ours. merge ( theirs) ) ,
220+ } ,
211221 ..self
212222 }
213223 }
@@ -330,6 +340,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
330340 fr_static,
331341 & mut outlives_constraints,
332342 errors_buffer,
343+ & definitions,
333344 ) ;
334345
335346 let ( constraint_sccs, scc_annotations) = if added_constraints {
@@ -363,6 +374,7 @@ pub(crate) fn rewrite_placeholder_outlives<'tcx>(
363374 fr_static : RegionVid ,
364375 outlives_constraints : & mut OutlivesConstraintSet < ' tcx > ,
365376 errors_buffer : & mut RegionErrors < ' tcx > ,
377+ definitions : & IndexVec < RegionVid , RegionDefinition < ' tcx > > ,
366378) -> bool {
367379 // Changed to `true` if we added any constraints and need to
368380 // recompute SCCs.
@@ -380,98 +392,97 @@ pub(crate) fn rewrite_placeholder_outlives<'tcx>(
380392
381393 let annotation = annotations[ scc] ;
382394
383- let Some ( PlaceholderReachability {
384- min_placeholder,
385- max_placeholder,
386- max_universe : ( max_placeholder_u, max_placeholder_u_rvid) ,
387- } ) = annotation. reachable_placeholders
395+ let Some ( PlaceholderReachability { min_placeholder, max_placeholder, max_universe } ) =
396+ annotation. reachable_placeholders
388397 else {
389398 debug ! ( "No placeholders reached from {scc:?}" ) ;
390399 continue ;
391400 } ;
392401
393- if let Some ( ( _ , us ) ) = annotation. is_placeholder
402+ if let Some ( us ) = annotation. is_placeholder
394403 && min_placeholder != max_placeholder
395404 {
396405 let illegally_outlived_r =
397- if min_placeholder == us { max_placeholder } else { min_placeholder } ;
406+ if min_placeholder == us. r { max_placeholder } else { min_placeholder } ;
398407 debug ! ( "Placeholder {us:?} outlives placeholder {illegally_outlived_r:?}" ) ;
399408 errors_buffer. push ( RegionErrorKind :: PlaceholderOutlivesIllegalRegion {
400- longer_fr : us,
409+ longer_fr : us. r ,
401410 illegally_outlived_r,
402411 } ) ;
412+ // FIXME: investigate if it's an actual improvement to drop early here
413+ // and stop reporting errors for this SCC since we are guaranteed to
414+ // have at least one.
403415 }
404416
405- if annotation. min_max_nameable_universe . can_name ( max_placeholder_u ) {
417+ if annotation. min_max_nameable_universe . can_name ( max_universe . u ) {
406418 debug ! ( "All placeholders nameable from {scc:?}!" ) ;
407419 continue ;
408420 }
409421
410422 debug ! (
411- "Placeholder {max_placeholder_u_rvid:?} with universe {max_placeholder_u_rvid :?} unnameable from {scc:?} represented by {:?}" ,
423+ "Placeholder {max_universe :?} unnameable from {scc:?} represented by {:?}" ,
412424 annotation. representative
413425 ) ;
414426
415427 // Figure out if we had our universe lowered by an existential
416428 // that cannot name us, a placeholder. This is an error.
417429 if let Some ( ( ex_u, ex_r) ) = annotation. worst_existential
418- && let Some ( ( pl_u , pl_r ) ) = annotation. is_placeholder
419- && ex_u. cannot_name ( pl_u )
430+ && let Some ( pl ) = annotation. is_placeholder
431+ && ex_u. cannot_name ( pl . u )
420432 {
421- debug ! ( "{pl_r:?} outlives existential {ex_r:?} that cannot name it!" ) ;
433+ debug ! ( "{pl:?} outlives existential {ex_r:?} that cannot name it!" ) ;
434+ // Prefer the representative region if it's also unnameable.
435+ let longer_fr = if let Representative :: Placeholder ( p) = annotation. representative
436+ && ex_u. cannot_name ( definitions[ p] . universe )
437+ {
438+ p
439+ } else {
440+ pl. r
441+ } ;
422442 errors_buffer. push ( RegionErrorKind :: PlaceholderOutlivesIllegalRegion {
423- longer_fr : pl_r ,
443+ longer_fr,
424444 illegally_outlived_r : ex_r,
425445 } ) ;
446+ // FIXME: we could `continue` here since there is no point in adding
447+ // 'r: 'static for this SCC now that it's already outlived an
448+ // existential it shouldn't, but we do anyway for compatibility with
449+ // earlier versions' output.
450+ } ;
426451
427- if annotation. representative . rvid ( ) != max_placeholder_u_rvid {
428- // We *additionally* have a case of an unnameable placeholder. Force the SCC
429- // to 'static to maintain compatibility with previous error reporting.
430- // Note: not required for correctness, since we already have an error and can't
431- // save the situation.
432- added_constraints = true ;
433- outlives_constraints. push ( OutlivesConstraint {
434- sup : annotation. representative . rvid ( ) ,
435- sub : fr_static,
436- category : ConstraintCategory :: OutlivesUnnameablePlaceholder (
437- max_placeholder_u_rvid,
438- ) ,
439- locations : Locations :: All ( rustc_span:: DUMMY_SP ) ,
440- span : rustc_span:: DUMMY_SP ,
441- variance_info : VarianceDiagInfo :: None ,
442- from_closure : false ,
443- } ) ;
444- }
445- } else {
446- // This SCC outlives a placeholder it can't name and must outlive 'static.
447-
448- let representative_rvid = annotation. representative . rvid ( ) ;
449-
450- if matches ! ( annotation. representative, Representative :: Placeholder ( _) ) {
451- // If this SCC is a placeholder, we fully describe what's
452- // wrong with a placeholder-reaches-placeholder error.
453- continue ;
454- }
455-
456- // FIXME: if we can extract a useful blame span here, future error
457- // reporting and constraint search can be simplified.
458-
459- assert ! (
460- representative_rvid != max_placeholder_u_rvid,
461- "The representative should never be unnameable!"
462- ) ;
463-
464- added_constraints = true ;
465- outlives_constraints. push ( OutlivesConstraint {
466- sup : representative_rvid,
467- sub : fr_static,
468- category : ConstraintCategory :: OutlivesUnnameablePlaceholder ( max_placeholder_u_rvid) ,
469- locations : Locations :: All ( rustc_span:: DUMMY_SP ) ,
470- span : rustc_span:: DUMMY_SP ,
471- variance_info : VarianceDiagInfo :: None ,
472- from_closure : false ,
473- } ) ;
452+ let representative_rvid = annotation. representative . rvid ( ) ;
453+
454+ if representative_rvid == max_universe. r {
455+ assert ! ( matches!( annotation. representative, Representative :: Placeholder ( _) ) ) ;
456+ // The unnameable placeholder *is* the representative.
457+ // If this SCC is represented by a placeholder `p` which cannot be named,
458+ // from its own SCC, `p` must have at some point reached a/an:
459+ // - existential region that could not name it (the `if` above)
460+ // - free region that lowered its universe (will flag an error in region
461+ // inference since `p` isn't empty)
462+ // - another placeholder (will flag an error above, but will reach here).
463+ //
464+ // To avoid adding the invalid constraint "'p: 'static` due to `'p` being
465+ // unnameable from the SCC represented by `'p`", we nope out early here
466+ // at no risk of soundness issues since at this point all paths lead
467+ // to an error.
468+ continue ;
474469 }
470+
471+ // This SCC outlives a placeholder it can't name and must outlive 'static.
472+
473+ // FIXME: if we can extract a useful blame span here, future error
474+ // reporting and constraint search can be simplified.
475+
476+ added_constraints = true ;
477+ outlives_constraints. push ( OutlivesConstraint {
478+ sup : representative_rvid,
479+ sub : fr_static,
480+ category : ConstraintCategory :: OutlivesUnnameablePlaceholder ( max_universe. r ) ,
481+ locations : Locations :: All ( rustc_span:: DUMMY_SP ) ,
482+ span : rustc_span:: DUMMY_SP ,
483+ variance_info : VarianceDiagInfo :: None ,
484+ from_closure : false ,
485+ } ) ;
475486 }
476487 added_constraints
477488}
0 commit comments