Skip to content

Commit 1d35d90

Browse files
committed
WIP
1 parent a209255 commit 1d35d90

File tree

4 files changed

+100
-9
lines changed

4 files changed

+100
-9
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

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

123-
/// Higher-ranked subtyping error.
123+
/// Higher-ranked subtyping error. A placeholder outlives
124+
/// either a location or a universal region.
124125
BoundUniversalRegionError {
125126
/// The placeholder free region.
126127
longer_fr: RegionVid,

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ use rustc_infer::infer::RegionVariableOrigin;
1313
use rustc_middle::bug;
1414
use rustc_middle::mir::ConstraintCategory;
1515
use rustc_middle::ty::{RegionVid, UniverseIndex};
16-
use tracing::{debug, trace};
16+
use tracing::{debug, instrument, trace};
1717

1818
use crate::constraints::graph::{ConstraintGraph, Normal, RegionGraph};
1919
use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
2020
use crate::consumers::OutlivesConstraint;
21-
use crate::diagnostics::UniverseInfo;
21+
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
2222
use crate::member_constraints::MemberConstraintSet;
2323
use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
2424
use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
@@ -293,6 +293,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
293293
constraints: MirTypeckRegionConstraints<'tcx>,
294294
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
295295
infcx: &BorrowckInferCtxt<'tcx>,
296+
errors_buffer: &mut RegionErrors<'tcx>,
296297
) -> LoweredConstraints<'tcx> {
297298
let universal_regions = &universal_region_relations.universal_regions;
298299
let (definitions, has_placeholders) = region_definitions(universal_regions, infcx);
@@ -359,6 +360,13 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
359360
&definitions,
360361
);
361362

363+
find_placeholder_mismatch_errors(
364+
&definitions,
365+
&constraint_sccs,
366+
&scc_annotations,
367+
errors_buffer,
368+
);
369+
362370
let (constraint_sccs, scc_annotations) = if added_constraints {
363371
let mut annotations = SccAnnotations::init(&definitions);
364372

@@ -510,3 +518,65 @@ fn find_region<'tcx>(
510518
// so if we don't find what we are looking for there's a bug somwehere.
511519
bug!("Should have found something!");
512520
}
521+
522+
/// Identify errors where placeholders illegally reach other regions, and generate
523+
/// errors stored into `errors_buffer`.
524+
///
525+
/// There are two sources of such errors:
526+
/// 1. A placeholder reaches (possibly transitively) another placeholder.
527+
/// 2. A placeholder `p` reaches (possibly transitively) an existential `e`,
528+
/// where `e` has an allowed maximum universe smaller than `p`'s.
529+
///
530+
/// There are other potential placeholder errors, but those are detected after
531+
/// region inference, since it may apply type tests or member constraints that
532+
/// alter the contents of SCCs and thus can't be detected at this point.
533+
#[instrument(skip(definitions, sccs, annotations, errors_buffer), level = "debug")]
534+
fn find_placeholder_mismatch_errors<'tcx>(
535+
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
536+
sccs: &Sccs<RegionVid, ConstraintSccIndex>,
537+
annotations: &SccAnnotations<'_, '_, RegionTracker>,
538+
errors_buffer: &mut RegionErrors<'tcx>,
539+
) {
540+
use NllRegionVariableOrigin::Placeholder;
541+
for (rvid, definition) in definitions.iter_enumerated() {
542+
let Placeholder(origin_a) = definition.origin else {
543+
continue;
544+
};
545+
546+
let scc = sccs.scc(rvid);
547+
let annotation = annotations.scc_to_annotation[scc];
548+
549+
if let Some(existental_that_cannot_name_rvid) =
550+
annotation.reaches_existential_that_cannot_name_us()
551+
{
552+
errors_buffer.push(RegionErrorKind::PlaceholderReachesExistentialThatCannotNameIt {
553+
longer_fr: rvid,
554+
existental_that_cannot_name_longer: existental_that_cannot_name_rvid,
555+
placeholder: origin_a,
556+
})
557+
}
558+
559+
let Some(other_placeholder) = annotation.reaches_other_placeholder(rvid) else {
560+
trace!("{rvid:?} reaches no other placeholders");
561+
continue;
562+
};
563+
564+
debug!(
565+
"Placeholder {rvid:?} of SCC {scc:?} reaches other placeholder {other_placeholder:?}"
566+
);
567+
568+
// FIXME SURELY there is a neater way to do this?
569+
let Placeholder(origin_b) = definitions[other_placeholder].origin else {
570+
unreachable!(
571+
"Region {rvid:?}, {other_placeholder:?} should be placeholders but aren't!"
572+
);
573+
};
574+
575+
errors_buffer.push(RegionErrorKind::PlaceholderMismatch {
576+
rvid_a: rvid,
577+
rvid_b: other_placeholder,
578+
origin_a,
579+
origin_b,
580+
});
581+
}
582+
}

compiler/rustc_borrowck/src/nll.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,13 @@ pub(crate) fn compute_regions<'tcx>(
114114
Rc::clone(&location_map),
115115
);
116116

117+
let mut placeholder_errors = RegionErrors::new(infcx.tcx);
118+
117119
let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
118120
constraints,
119121
&universal_region_relations,
120122
infcx,
123+
&mut placeholder_errors,
121124
);
122125

123126
// If requested, emit legacy polonius facts.
@@ -167,9 +170,17 @@ pub(crate) fn compute_regions<'tcx>(
167170
});
168171

169172
// Solve the region constraints.
170-
let (closure_region_requirements, nll_errors) =
173+
let (closure_region_requirements, region_inference_errors) =
171174
regioncx.solve(infcx, body, polonius_output.clone());
172175

176+
let nll_errors = if region_inference_errors.has_errors().is_some() {
177+
debug!("Errors already reported, skipping these: {placeholder_errors:?}");
178+
region_inference_errors
179+
} else {
180+
// Only flag the higher-kinded bounds errors if there are no borrowck errors.
181+
placeholder_errors
182+
};
183+
173184
if let Some(guar) = nll_errors.has_errors() {
174185
// Suppress unhelpful extra errors in `infer_opaque_types`.
175186
infcx.set_tainted_by_errors(guar);

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,14 +1531,23 @@ impl<'tcx> RegionInferenceContext<'tcx> {
15311531
let longer_fr_scc = self.constraint_sccs.scc(longer_fr);
15321532
debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,);
15331533

1534+
// FIXME(amandasystems): This is an inlined version of elements_contained_in, without
1535+
// placeholders, which are handled separately. Later, when placeholders are removed
1536+
// from scc_values, this part will just be elements_contained_in():
1537+
let mut non_placeholder_regions_in = self
1538+
.scc_values
1539+
.locations_outlived_by(longer_fr_scc)
1540+
.map(RegionElement::Location)
1541+
.chain(
1542+
self.scc_values
1543+
.universal_regions_outlived_by(longer_fr_scc)
1544+
.map(RegionElement::RootUniversalRegion),
1545+
);
1546+
15341547
// If we have some bound universal region `'a`, then the only
15351548
// elements it can contain is itself -- we don't know anything
15361549
// else about it!
1537-
if let Some(error_element) = self
1538-
.scc_values
1539-
.elements_contained_in(longer_fr_scc)
1540-
.find(|e| *e != RegionElement::PlaceholderRegion(placeholder))
1541-
{
1550+
if let Some(error_element) = non_placeholder_regions_in.next() {
15421551
// Stop after the first error, it gets too noisy otherwise, and does not provide more information.
15431552
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
15441553
longer_fr,

0 commit comments

Comments
 (0)