Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
93fc946
Move handling of placeholder errors to before region inference
amandasystems Sep 3, 2025
00a5015
Revise the tests for `coroutine/auto-trait-regions`
amandasystems Jun 17, 2025
93cddc9
Avoid adding edges to static where we already flag other errors
amandasystems Aug 27, 2025
8f9c89c
Only flag the error for placeholder-existential failures if there is
amandasystems Sep 25, 2025
c90b964
Clarify when and why we can skip adding the : 'static constraints
amandasystems Sep 18, 2025
5ebced9
Be more restrictive of when we add placeholder-existential errors
amandasystems Sep 24, 2025
fe03861
Remove precise placeholder tracking from region inference
amandasystems Oct 9, 2025
6db3b33
More explicit version of placeholder constraint handling
amandasystems Nov 3, 2025
7e758c4
Simplify the placeholder error reporting, add skipping logic
amandasystems Nov 3, 2025
be81d10
Simplify error handling & placeholder reachability
amandasystems Nov 6, 2025
42bac69
Simplify some of the error handling for placeholder errors
amandasystems Nov 7, 2025
e8c7834
Switch SCC annotations to a update style; it's more ergonomic
amandasystems Nov 10, 2025
0115818
Some more code cleanup
amandasystems Nov 10, 2025
38e472e
Remove option use according to review comments
amandasystems Nov 10, 2025
656caf6
One of the duplicate errors will not be flagged here
amandasystems Nov 10, 2025
07c353b
Report fewer duplicate errors in tests
amandasystems Nov 24, 2025
fbe2418
Only annotate region graph SCCs with their representative for functio…
amandasystems Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_
use tracing::{debug, instrument};

use crate::MirBorrowckCtxt;
use crate::region_infer::values::RegionElement;
use crate::session_diagnostics::{
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
};
Expand All @@ -49,11 +48,12 @@ impl<'tcx> UniverseInfo<'tcx> {
UniverseInfo::RelateTys { expected, found }
}

/// Report an error where an element erroneously made its way into `placeholder`.
pub(crate) fn report_erroneous_element(
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
placeholder: ty::PlaceholderRegion,
error_element: RegionElement,
error_element: Option<ty::PlaceholderRegion>,
cause: ObligationCause<'tcx>,
) {
match *self {
Expand Down Expand Up @@ -153,10 +153,17 @@ pub(crate) trait TypeOpInfo<'tcx> {
&self,
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
placeholder: ty::PlaceholderRegion,
error_element: RegionElement,
error_element: Option<ty::PlaceholderRegion>,
cause: ObligationCause<'tcx>,
) {
let tcx = mbcx.infcx.tcx;

// FIXME: this logic is convoluted and strange, and
// we should probably just use the placeholders we get
// as arguments! However, upstream error reporting code
// needs adaptations for that to work (this universe is
// neither the assigned one, nor the calculated one but
// some base-shifted one for some reason?).
let base_universe = self.base_universe();
debug!(?base_universe);

Expand All @@ -172,20 +179,16 @@ pub(crate) trait TypeOpInfo<'tcx> {
ty::Placeholder { universe: adjusted_universe.into(), bound: placeholder.bound },
);

let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) =
error_element
{
let adjusted_universe =
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
Copy link
Contributor Author

@amandasystems amandasystems Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the "checked sub" part is what really broke me here. Why are universes being adjusted? What's a base universe? And why can the subtraction sometimes overflow?!?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, these are the only reads of base_universe on CanonicalTypeOpDeeplyNormalizeGoal, CanonicalTypeOpAscribeUserTypeGoal and InstantiateOpaqueType.

// FIXME: one day this should just be error_element, but see above about the adjusted universes. At that point, this method can probably be removed entirely.
let error_region = error_element.and_then(|e| {
let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32());
adjusted_universe.map(|adjusted| {
ty::Region::new_placeholder(
tcx,
ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound },
ty::Placeholder { universe: adjusted.into(), bound: e.bound },
)
})
} else {
None
};
});

debug!(?placeholder_region);

Expand Down
115 changes: 39 additions & 76 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use tracing::{debug, instrument, trace};

use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
use crate::nll::ConstraintDescription;
use crate::region_infer::values::RegionElement;
use crate::region_infer::{BlameConstraint, TypeTest};
use crate::session_diagnostics::{
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
Expand Down Expand Up @@ -104,15 +103,9 @@ pub(crate) enum RegionErrorKind<'tcx> {
/// A generic bound failure for a type test (`T: 'a`).
TypeTestError { type_test: TypeTest<'tcx> },

/// Higher-ranked subtyping error.
BoundUniversalRegionError {
/// The placeholder free region.
longer_fr: RegionVid,
/// The region element that erroneously must be outlived by `longer_fr`.
error_element: RegionElement,
/// The placeholder region.
placeholder: ty::PlaceholderRegion,
},
/// 'p outlives 'r, which does not hold. 'p is always a placeholder
/// and 'r is some other region.
PlaceholderOutlivesIllegalRegion { longer_fr: RegionVid, illegally_outlived_r: RegionVid },

/// Any other lifetime error.
RegionError {
Expand Down Expand Up @@ -205,60 +198,47 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let tcx = self.infcx.tcx;

// find generic associated types in the given region 'lower_bound'
let gat_id_and_generics = self
let scc = self.regioncx.constraint_sccs().scc(lower_bound);
let Some(gat_hir_id) = self
.regioncx
.placeholders_contained_in(lower_bound)
.map(|placeholder| {
if let Some(id) = placeholder.bound.kind.get_id()
&& let Some(placeholder_id) = id.as_local()
&& let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
&& let Some(generics_impl) =
tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
{
Some((gat_hir_id, generics_impl))
} else {
None
}
})
.collect::<Vec<_>>();
debug!(?gat_id_and_generics);
.placeholder_representative(scc)
.and_then(|placeholder| placeholder.bound.kind.get_id())
.and_then(|id| id.as_local())
.map(|local| self.infcx.tcx.local_def_id_to_hir_id(local))
else {
return;
};

// Look for the where-bound which introduces the placeholder.
// As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>`
// and `T: for<'a> Trait`<'a>.
let mut hrtb_bounds = vec![];
gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| {
for pred in generics.predicates {
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
pred.kind
else {
continue;
};
if bound_generic_params
.iter()
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
.is_some()
{
for bound in *bounds {
hrtb_bounds.push(bound);
}
} else {
for bound in *bounds {
if let Trait(trait_bound) = bound {
if trait_bound
.bound_generic_params
.iter()
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
.is_some()
{
hrtb_bounds.push(bound);
return;
}
}
}

// FIXME(amandasystems) we can probably flatten this.
for pred in self
.infcx
.tcx
.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
.generics()
.map(|gen_impl| gen_impl.predicates)
.into_iter()
.flatten()
{
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
pred.kind
else {
continue;
};
if bound_generic_params
.iter()
.rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
.is_some()
{
for bound in *bounds {
hrtb_bounds.push(bound);
}
}
});
}
debug!(?hrtb_bounds);

let mut suggestions = vec![];
Expand Down Expand Up @@ -361,28 +341,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}

RegionErrorKind::BoundUniversalRegionError {
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
longer_fr,
placeholder,
error_element,
illegally_outlived_r,
} => {
let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);

// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let cause = self
.regioncx
.best_blame_constraint(
longer_fr,
NllRegionVariableOrigin::Placeholder(placeholder),
error_vid,
)
.0
.cause;

let universe = placeholder.universe;
let universe_info = self.regioncx.universe_info(universe);

universe_info.report_erroneous_element(self, placeholder, error_element, cause);
self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r)
}

RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
Expand Down
Loading
Loading