Skip to content

Commit 7e758c4

Browse files
committed
Simplify the placeholder error reporting, add skipping logic
1 parent 6db3b33 commit 7e758c4

File tree

5 files changed

+60
-117
lines changed

5 files changed

+60
-117
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Lines changed: 9 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -104,27 +104,10 @@ pub(crate) enum RegionErrorKind<'tcx> {
104104
/// A generic bound failure for a type test (`T: 'a`).
105105
TypeTestError { type_test: TypeTest<'tcx> },
106106

107-
/// 'a outlives 'b, and both are placeholders.
108-
PlaceholderOutlivesPlaceholder {
109-
rvid_a: RegionVid,
110-
rvid_b: RegionVid,
111-
origin_a: ty::PlaceholderRegion,
112-
origin_b: ty::PlaceholderRegion,
113-
},
114-
115-
/// Indicates that a placeholder has a universe too large for one
116-
/// of its member existentials, or, equivalently, that there is
117-
/// a path through the outlives constraint graph from a placeholder
118-
/// to an existential region that cannot name it.
119-
PlaceholderOutlivesExistentialThatCannotNameIt {
120-
/// the placeholder that transitively outlives an
121-
/// existential that shouldn't leak into it
122-
longer_fr: RegionVid,
123-
/// The existential leaking into `longer_fr`.
124-
existential_that_cannot_name_longer: RegionVid,
125-
// `longer_fr`'s originating placeholder region.
126-
placeholder: ty::PlaceholderRegion,
127-
},
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.
110+
PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid },
128111

129112
/// Higher-ranked subtyping error. A placeholder outlives
130113
/// either a location or a universal region.
@@ -133,8 +116,6 @@ pub(crate) enum RegionErrorKind<'tcx> {
133116
longer_fr: RegionVid,
134117
/// The region element that erroneously must be outlived by `longer_fr`.
135118
error_element: RegionElement,
136-
/// The placeholder region.
137-
placeholder: ty::PlaceholderRegion,
138119
},
139120

140121
/// Any other lifetime error.
@@ -361,53 +342,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
361342

362343
RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
363344
longer_fr,
364-
placeholder,
365345
error_element,
366346
} => self.report_erroneous_rvid_reaches_placeholder(
367347
longer_fr,
368-
placeholder,
369348
self.regioncx.region_from_element(longer_fr, &error_element),
370349
),
371-
RegionErrorKind::PlaceholderOutlivesPlaceholder {
372-
rvid_a,
373-
rvid_b,
374-
origin_a,
375-
origin_b,
376-
} => {
377-
debug!(
378-
"Placeholder mismatch: {rvid_a:?} ({origin_a:?}) reaches {rvid_b:?} ({origin_b:?})"
379-
);
380-
381-
let cause = self
382-
.regioncx
383-
.best_blame_constraint(
384-
rvid_a,
385-
NllRegionVariableOrigin::Placeholder(origin_a),
386-
rvid_b,
387-
)
388-
.0
389-
.cause;
390-
391-
// FIXME We may be able to shorten the code path here, and immediately
392-
// report a `RegionResolutionError::UpperBoundUniverseConflict`, but
393-
// that's left for a future refactoring.
394-
self.regioncx.universe_info(origin_a.universe).report_erroneous_element(
395-
self,
396-
origin_a,
397-
Some(origin_b),
398-
cause,
399-
);
400-
}
401350

402-
RegionErrorKind::PlaceholderOutlivesExistentialThatCannotNameIt {
403-
longer_fr,
404-
existential_that_cannot_name_longer,
405-
placeholder,
406-
} => self.report_erroneous_rvid_reaches_placeholder(
351+
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
407352
longer_fr,
408-
placeholder,
409-
existential_that_cannot_name_longer,
410-
),
353+
illegally_outlived_r,
354+
} => {
355+
self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r)
356+
}
411357

412358
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
413359
if is_reported {

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,31 @@ pub(crate) struct LoweredConstraints<'tcx> {
3535
}
3636

3737
impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
38-
pub(crate) fn init(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
39-
Self { scc_to_annotation: IndexVec::new(), definitions }
38+
pub(crate) fn with_checking_placeholders(
39+
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
40+
) -> Self {
41+
Self { scc_to_annotation: IndexVec::new(), definitions, check_placeholders: true }
42+
}
43+
44+
pub(crate) fn without_checking_placeholders(
45+
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
46+
) -> Self {
47+
Self { scc_to_annotation: IndexVec::new(), definitions, check_placeholders: true }
4048
}
4149
}
4250

4351
/// A Visitor for SCC annotation construction.
4452
pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
4553
pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
4654
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
55+
/// True if we apply extra validity checking logic to placeholder
56+
/// regions, false to skip it. Used only for performance reasons.
57+
check_placeholders: bool,
4758
}
4859

4960
impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
5061
fn new(&self, element: RegionVid) -> RegionTracker {
51-
RegionTracker::new(element, &self.definitions[element])
62+
RegionTracker::new(element, &self.definitions[element], self.check_placeholders)
5263
}
5364

5465
fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
@@ -199,7 +210,11 @@ pub(crate) struct RegionTracker {
199210
}
200211

201212
impl RegionTracker {
202-
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
213+
pub(crate) fn new(
214+
rvid: RegionVid,
215+
definition: &RegionDefinition<'_>,
216+
check_placeholders: bool,
217+
) -> Self {
203218
use NllRegionVariableOrigin::*;
204219
use PlaceholderConstraints::*;
205220
use PlaceholderReachability::*;
@@ -222,13 +237,13 @@ impl RegionTracker {
222237
max_placeholder: rvid,
223238
},
224239
min_max_nameable_universe,
225-
exception: Some(Name(definition.universe)),
240+
exception: check_placeholders.then_some(Name(definition.universe)),
226241
representative,
227242
},
228243
Existential { .. } => Self {
229244
reachable_placeholders: NoPlaceholders,
230245
min_max_nameable_universe,
231-
exception: Some(NameableBy(rvid, definition.universe)),
246+
exception: check_placeholders.then_some(NameableBy(rvid, definition.universe)),
232247
representative,
233248
},
234249
}
@@ -439,7 +454,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
439454
)
440455
};
441456

442-
let mut scc_annotations = SccAnnotations::init(&definitions);
457+
let mut scc_annotations = SccAnnotations::with_checking_placeholders(&definitions);
443458
let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
444459

445460
// This code structure is a bit convoluted because it allows for a planned
@@ -475,7 +490,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
475490
);
476491

477492
let (constraint_sccs, scc_annotations) = if added_constraints {
478-
let mut annotations = SccAnnotations::init(&definitions);
493+
let mut annotations = SccAnnotations::without_checking_placeholders(&definitions);
479494

480495
// We changed the constraint set and so must recompute SCCs.
481496
// Optimisation opportunity: if we can add them incrementally (and that's
@@ -583,44 +598,21 @@ fn find_placeholder_mismatch_errors<'tcx>(
583598
) {
584599
use NllRegionVariableOrigin::Placeholder;
585600
for (rvid, definition) in definitions.iter_enumerated() {
586-
let Placeholder(origin_a) = definition.origin else {
601+
let Placeholder(_) = definition.origin else {
587602
continue;
588603
};
589604

590605
let scc = sccs.scc(rvid);
591606
let annotation = annotations.scc_to_annotation[scc];
592607

593-
if let Some(cannot_name_rvid) = annotation.reaches_existential_that_cannot_name_us() {
594-
debug!("Existential {cannot_name_rvid:?} lowered our universe...");
595-
596-
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesExistentialThatCannotNameIt {
608+
if let Some(illegally_outlived_r) = annotation
609+
.reaches_existential_that_cannot_name_us()
610+
.or_else(|| annotation.reaches_other_placeholder(rvid))
611+
{
612+
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion {
597613
longer_fr: rvid,
598-
existential_that_cannot_name_longer: cannot_name_rvid,
599-
placeholder: origin_a,
614+
illegally_outlived_r,
600615
})
601616
}
602-
603-
let Some(other_placeholder) = annotation.reaches_other_placeholder(rvid) else {
604-
trace!("{rvid:?} reaches no other placeholders");
605-
continue;
606-
};
607-
608-
debug!(
609-
"Placeholder {rvid:?} of SCC {scc:?} reaches other placeholder {other_placeholder:?}"
610-
);
611-
612-
// FIXME SURELY there is a neater way to do this?
613-
let Placeholder(origin_b) = definitions[other_placeholder].origin else {
614-
unreachable!(
615-
"Region {rvid:?}, {other_placeholder:?} should be placeholders but aren't!"
616-
);
617-
};
618-
619-
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesPlaceholder {
620-
rvid_a: rvid,
621-
rvid_b: other_placeholder,
622-
origin_a,
623-
origin_b,
624-
});
625617
}
626618
}

compiler/rustc_borrowck/src/lib.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2692,24 +2692,30 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
26922692
}
26932693
}
26942694

2695-
/// Report that longer_fr: shorter_fr, which doesn't hold,
2696-
/// where longer_fr is a placeholder from `placeholder`.
2695+
/// Report that `longer_fr: error_vid`, which doesn't hold,
2696+
/// where `longer_fr` is a placeholder.
26972697
fn report_erroneous_rvid_reaches_placeholder(
26982698
&mut self,
26992699
longer_fr: RegionVid,
2700-
placeholder: ty::Placeholder<ty::BoundRegion>,
27012700
error_vid: RegionVid,
27022701
) {
2702+
use NllRegionVariableOrigin::*;
2703+
2704+
let origin_longer = self.regioncx.definitions[longer_fr].origin;
2705+
27032706
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
2704-
let cause = self
2705-
.regioncx
2706-
.best_blame_constraint(
2707-
longer_fr,
2708-
NllRegionVariableOrigin::Placeholder(placeholder),
2709-
error_vid,
2710-
)
2711-
.0
2712-
.cause;
2707+
let cause =
2708+
self.regioncx.best_blame_constraint(longer_fr, origin_longer, error_vid).0.cause;
2709+
2710+
let Placeholder(placeholder) = origin_longer else {
2711+
bug!("Expected {longer_fr:?} to come from placeholder!");
2712+
};
2713+
2714+
// FIXME: Is throwing away the existential region really the best here?
2715+
let error_region = match self.regioncx.definitions[error_vid].origin {
2716+
FreeRegion | Existential { .. } => None,
2717+
Placeholder(other_placeholder) => Some(other_placeholder),
2718+
};
27132719

27142720
// FIXME these methods should have better names, and also probably not be this generic.
27152721
// FIXME note that we *throw away* the error element here! We probably want to
@@ -2718,7 +2724,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
27182724
self.regioncx.universe_info(placeholder.universe).report_erroneous_element(
27192725
self,
27202726
placeholder,
2721-
None,
2727+
error_region,
27222728
cause,
27232729
);
27242730
}

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
12491249
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
12501250
longer_fr,
12511251
error_element,
1252-
placeholder,
12531252
});
12541253
} else {
12551254
debug!("check_bound_universal_region: all bounds satisfied");

compiler/rustc_borrowck/src/region_infer/opaque_types/region_ctxt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
5656
)
5757
};
5858

59-
let mut scc_annotations = SccAnnotations::init(&definitions);
59+
let mut scc_annotations = SccAnnotations::without_checking_placeholders(&definitions);
6060
let mut constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
6161

6262
let added_constraints = crate::handle_placeholders::rewrite_placeholder_outlives(
@@ -67,7 +67,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
6767
);
6868

6969
if added_constraints {
70-
scc_annotations = SccAnnotations::init(&definitions);
70+
scc_annotations = SccAnnotations::without_checking_placeholders(&definitions);
7171
constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
7272
}
7373

0 commit comments

Comments
 (0)