Skip to content

Commit 5df668a

Browse files
committed
Simplify some of the error handling for placeholder errors
1 parent 603b548 commit 5df668a

File tree

4 files changed

+112
-127
lines changed

4 files changed

+112
-127
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use tracing::{debug, instrument, trace};
2929

3030
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
3131
use crate::nll::ConstraintDescription;
32-
use crate::region_infer::values::RegionElement;
3332
use crate::region_infer::{BlameConstraint, TypeTest};
3433
use crate::session_diagnostics::{
3534
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
@@ -104,20 +103,10 @@ pub(crate) enum RegionErrorKind<'tcx> {
104103
/// A generic bound failure for a type test (`T: 'a`).
105104
TypeTestError { type_test: TypeTest<'tcx> },
106105

107-
/// 'a outlives 'b, which does not hold. 'a is always a
108-
/// placeholder and 'b is either an existential that cannot name
109-
/// 'a, or another placeholder.
106+
/// 'p outlives 'r, which does not hold. 'p is always a placeholder
107+
/// and 'r is some other region.
110108
PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid },
111109

112-
/// Higher-ranked subtyping error. A placeholder outlives
113-
/// either a location or a universal region.
114-
PlaceholderOutlivesLocationOrUniversal {
115-
/// The placeholder free region.
116-
longer_fr: RegionVid,
117-
/// The region element that erroneously must be outlived by `longer_fr`.
118-
error_element: RegionElement,
119-
},
120-
121110
/// Any other lifetime error.
122111
RegionError {
123112
/// The origin of the region.
@@ -340,14 +329,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
340329
}
341330
}
342331

343-
RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
344-
longer_fr,
345-
error_element,
346-
} => self.report_erroneous_rvid_reaches_placeholder(
347-
longer_fr,
348-
self.regioncx.region_from_element(longer_fr, &error_element),
349-
),
350-
351332
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
352333
longer_fr,
353334
illegally_outlived_r,

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 101 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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+
46
use rustc_data_structures::frozen::Frozen;
57
use rustc_data_structures::fx::FxIndexMap;
68
use rustc_data_structures::graph::scc;
@@ -63,7 +65,7 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
6365
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
6466
pub(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-
177194
impl 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

Comments
 (0)