Skip to content

Commit 197e49b

Browse files
committed
WIP
1 parent 1d35d90 commit 197e49b

File tree

3 files changed

+104
-5
lines changed

3 files changed

+104
-5
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,31 @@ pub(crate) enum RegionErrorKind<'tcx> {
120120
member_region: ty::Region<'tcx>,
121121
},
122122

123+
/// 'a outlives 'b, and both are placeholders.
124+
PlaceholderOutlivesPlaceholder {
125+
rvid_a: RegionVid,
126+
rvid_b: RegionVid,
127+
origin_a: ty::PlaceholderRegion,
128+
origin_b: ty::PlaceholderRegion,
129+
},
130+
131+
/// Indicates that a placeholder has a universe too large for one
132+
/// of its member existentials, or, equivalently, that there is
133+
/// a path through the outlives constraint graph from a placeholder
134+
/// to an existential region that cannot name it.
135+
PlaceholderOutlivesExistentialThatCannotNameIt {
136+
/// the placeholder that transitively outlives an
137+
/// existential that shouldn't leak into it
138+
longer_fr: RegionVid,
139+
/// The existential leaking into `longer_fr`.
140+
existental_that_cannot_name_longer: RegionVid,
141+
// `longer_fr`'s originating placeholder region.
142+
placeholder: ty::PlaceholderRegion,
143+
},
144+
123145
/// Higher-ranked subtyping error. A placeholder outlives
124146
/// either a location or a universal region.
125-
BoundUniversalRegionError {
147+
PlaceholderOutlivesLocationOrUniversal {
126148
/// The placeholder free region.
127149
longer_fr: RegionVid,
128150
/// The region element that erroneously must be outlived by `longer_fr`.
@@ -389,7 +411,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
389411
}
390412
}
391413

392-
RegionErrorKind::BoundUniversalRegionError {
414+
RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
393415
longer_fr,
394416
placeholder,
395417
error_element,
@@ -412,6 +434,46 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
412434

413435
universe_info.report_erroneous_element(self, placeholder, error_element, cause);
414436
}
437+
RegionErrorKind::PlaceholderOutlivesPlaceholder {
438+
rvid_a,
439+
rvid_b,
440+
origin_a,
441+
origin_b,
442+
} => {
443+
debug!(
444+
"Placeholder mismatch: {rvid_a:?} ({origin_a:?}) reaches {rvid_b:?} ({origin_b:?})"
445+
);
446+
447+
let cause = self
448+
.regioncx
449+
.best_blame_constraint(
450+
rvid_a,
451+
NllRegionVariableOrigin::Placeholder(origin_a),
452+
rvid_b,
453+
)
454+
.0
455+
.cause;
456+
457+
// FIXME We may be able to shorten the code path here, and immediately
458+
// report a `RegionResolutionError::UpperBoundUniverseConflict`, but
459+
// that's left for a future refactoring.
460+
self.regioncx.universe_info(origin_a.universe).report_erroneous_element(
461+
self,
462+
origin_a,
463+
Some(origin_b),
464+
cause,
465+
);
466+
}
467+
468+
RegionErrorKind::PlaceholderOutlivesExistentialThatCannotNameIt {
469+
longer_fr,
470+
existental_that_cannot_name_longer,
471+
placeholder,
472+
} => self.report_erroneous_rvid_reaches_placeholder(
473+
longer_fr,
474+
placeholder,
475+
existental_that_cannot_name_longer,
476+
),
415477

416478
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
417479
if is_reported {

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
@@ -549,7 +586,7 @@ fn find_placeholder_mismatch_errors<'tcx>(
549586
if let Some(existental_that_cannot_name_rvid) =
550587
annotation.reaches_existential_that_cannot_name_us()
551588
{
552-
errors_buffer.push(RegionErrorKind::PlaceholderReachesExistentialThatCannotNameIt {
589+
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesExistentialThatCannotNameIt {
553590
longer_fr: rvid,
554591
existental_that_cannot_name_longer: existental_that_cannot_name_rvid,
555592
placeholder: origin_a,
@@ -572,7 +609,7 @@ fn find_placeholder_mismatch_errors<'tcx>(
572609
);
573610
};
574611

575-
errors_buffer.push(RegionErrorKind::PlaceholderMismatch {
612+
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesPlaceholder {
576613
rvid_a: rvid,
577614
rvid_b: other_placeholder,
578615
origin_a,

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
15491549
// else about it!
15501550
if let Some(error_element) = non_placeholder_regions_in.next() {
15511551
// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
1552-
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
1552+
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
15531553
longer_fr,
15541554
error_element,
15551555
placeholder,

0 commit comments

Comments
 (0)