Skip to content

Commit b10c525

Browse files
Auto merge of #142623 - amandasystems:early-placeholder-errors, r=<try>
Move placeholder error handling to before region inference
2 parents f524236 + 05d58ab commit b10c525

File tree

14 files changed

+466
-416
lines changed

14 files changed

+466
-416
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_
2424
use tracing::{debug, instrument};
2525

2626
use crate::MirBorrowckCtxt;
27-
use crate::region_infer::values::RegionElement;
2827
use crate::session_diagnostics::{
2928
HigherRankedErrorCause, HigherRankedLifetimeError, HigherRankedSubtypeError,
3029
};
@@ -49,11 +48,12 @@ impl<'tcx> UniverseInfo<'tcx> {
4948
UniverseInfo::RelateTys { expected, found }
5049
}
5150

51+
/// Report an error where an element erroneously made its way into `placeholder`.
5252
pub(crate) fn report_erroneous_element(
5353
&self,
5454
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
5555
placeholder: ty::PlaceholderRegion,
56-
error_element: RegionElement,
56+
error_element: Option<ty::PlaceholderRegion>,
5757
cause: ObligationCause<'tcx>,
5858
) {
5959
match *self {
@@ -153,10 +153,17 @@ pub(crate) trait TypeOpInfo<'tcx> {
153153
&self,
154154
mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>,
155155
placeholder: ty::PlaceholderRegion,
156-
error_element: RegionElement,
156+
error_element: Option<ty::PlaceholderRegion>,
157157
cause: ObligationCause<'tcx>,
158158
) {
159159
let tcx = mbcx.infcx.tcx;
160+
161+
// FIXME: this logic is convoluted and strange, and
162+
// we should probably just use the placeholders we get
163+
// as arguments! However, upstream error reporting code
164+
// needs adaptations for that to work (this universe is
165+
// neither the assigned one, nor the calculated one but
166+
// some base-shifted one for some reason?).
160167
let base_universe = self.base_universe();
161168
debug!(?base_universe);
162169

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

175-
let error_region = if let RegionElement::PlaceholderRegion(error_placeholder) =
176-
error_element
177-
{
178-
let adjusted_universe =
179-
error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
182+
// 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.
183+
let error_region = error_element.and_then(|e| {
184+
let adjusted_universe = e.universe.as_u32().checked_sub(base_universe.as_u32());
180185
adjusted_universe.map(|adjusted| {
181186
ty::Region::new_placeholder(
182187
tcx,
183-
ty::Placeholder { universe: adjusted.into(), bound: error_placeholder.bound },
188+
ty::Placeholder { universe: adjusted.into(), bound: e.bound },
184189
)
185190
})
186-
} else {
187-
None
188-
};
191+
});
189192

190193
debug!(?placeholder_region);
191194

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

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

107-
/// Higher-ranked subtyping error.
108-
BoundUniversalRegionError {
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+
},
128+
129+
/// Higher-ranked subtyping error. A placeholder outlives
130+
/// either a location or a universal region.
131+
PlaceholderOutlivesLocationOrUniversal {
109132
/// The placeholder free region.
110133
longer_fr: RegionVid,
111134
/// The region element that erroneously must be outlived by `longer_fr`.
@@ -201,64 +224,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
201224
&self,
202225
diag: &mut Diag<'_>,
203226
lower_bound: RegionVid,
204-
) {
227+
) -> Option<()> {
205228
let tcx = self.infcx.tcx;
206229

207230
// find generic associated types in the given region 'lower_bound'
208-
let gat_id_and_generics = self
209-
.regioncx
210-
.placeholders_contained_in(lower_bound)
211-
.map(|placeholder| {
212-
if let Some(id) = placeholder.bound.kind.get_id()
213-
&& let Some(placeholder_id) = id.as_local()
214-
&& let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
215-
&& let Some(generics_impl) =
216-
tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
217-
{
218-
Some((gat_hir_id, generics_impl))
219-
} else {
220-
None
221-
}
222-
})
223-
.collect::<Vec<_>>();
224-
debug!(?gat_id_and_generics);
231+
let scc = self.regioncx.constraint_sccs().scc(lower_bound);
232+
let placeholder: ty::PlaceholderRegion = self.regioncx.placeholder_representative(scc)?;
233+
let placeholder_id = placeholder.bound.kind.get_id()?.as_local()?;
234+
let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id);
235+
let generics_impl =
236+
self.infcx.tcx.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id)).generics()?;
225237

226238
// Look for the where-bound which introduces the placeholder.
227239
// As we're using the HIR, we need to handle both `for<'a> T: Trait<'a>`
228240
// and `T: for<'a> Trait`<'a>.
229241
let mut hrtb_bounds = vec![];
230-
gat_id_and_generics.iter().flatten().for_each(|&(gat_hir_id, generics)| {
231-
for pred in generics.predicates {
232-
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
233-
pred.kind
234-
else {
235-
continue;
236-
};
237-
if bound_generic_params
238-
.iter()
239-
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
240-
.is_some()
241-
{
242-
for bound in *bounds {
243-
hrtb_bounds.push(bound);
244-
}
245-
} else {
246-
for bound in *bounds {
247-
if let Trait(trait_bound) = bound {
248-
if trait_bound
249-
.bound_generic_params
250-
.iter()
251-
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
252-
.is_some()
253-
{
254-
hrtb_bounds.push(bound);
255-
return;
256-
}
257-
}
258-
}
242+
243+
for pred in generics_impl.predicates {
244+
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
245+
pred.kind
246+
else {
247+
continue;
248+
};
249+
if bound_generic_params
250+
.iter()
251+
.rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
252+
.is_some()
253+
{
254+
for bound in *bounds {
255+
hrtb_bounds.push(bound);
259256
}
260257
}
261-
});
258+
}
262259
debug!(?hrtb_bounds);
263260

264261
let mut suggestions = vec![];
@@ -304,6 +301,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
304301
Applicability::MaybeIncorrect,
305302
);
306303
}
304+
Some(())
307305
}
308306

309307
/// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.
@@ -361,30 +359,56 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
361359
}
362360
}
363361

364-
RegionErrorKind::BoundUniversalRegionError {
362+
RegionErrorKind::PlaceholderOutlivesLocationOrUniversal {
365363
longer_fr,
366364
placeholder,
367365
error_element,
366+
} => self.report_erroneous_rvid_reaches_placeholder(
367+
longer_fr,
368+
placeholder,
369+
self.regioncx.region_from_element(longer_fr, &error_element),
370+
),
371+
RegionErrorKind::PlaceholderOutlivesPlaceholder {
372+
rvid_a,
373+
rvid_b,
374+
origin_a,
375+
origin_b,
368376
} => {
369-
let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
377+
debug!(
378+
"Placeholder mismatch: {rvid_a:?} ({origin_a:?}) reaches {rvid_b:?} ({origin_b:?})"
379+
);
370380

371-
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
372381
let cause = self
373382
.regioncx
374383
.best_blame_constraint(
375-
longer_fr,
376-
NllRegionVariableOrigin::Placeholder(placeholder),
377-
error_vid,
384+
rvid_a,
385+
NllRegionVariableOrigin::Placeholder(origin_a),
386+
rvid_b,
378387
)
379388
.0
380389
.cause;
381390

382-
let universe = placeholder.universe;
383-
let universe_info = self.regioncx.universe_info(universe);
384-
385-
universe_info.report_erroneous_element(self, placeholder, error_element, cause);
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+
);
386400
}
387401

402+
RegionErrorKind::PlaceholderOutlivesExistentialThatCannotNameIt {
403+
longer_fr,
404+
existential_that_cannot_name_longer,
405+
placeholder,
406+
} => self.report_erroneous_rvid_reaches_placeholder(
407+
longer_fr,
408+
placeholder,
409+
existential_that_cannot_name_longer,
410+
),
411+
388412
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
389413
if is_reported {
390414
self.report_region_error(

0 commit comments

Comments
 (0)