Skip to content

Commit 4958ec8

Browse files
committed
Remove precise placeholder tracking during region inference
Placeholders are now handled mostly by rewriting constraints as a pre-computation step, so precisely tracking which placeholder end up in which region is no longer necessary.
1 parent 199f961 commit 4958ec8

File tree

7 files changed

+97
-290
lines changed

7 files changed

+97
-290
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ pub(crate) trait TypeOpInfo<'tcx> {
179179
cause: ObligationCause<'tcx>,
180180
) {
181181
let tcx = mbcx.infcx.tcx;
182-
183182
// FIXME: these adjusted universes are not (always) the same ones as we compute
184183
// earlier. They probably should be, but the logic downstream is complicated,
185184
// and assumes they use whatever this is.

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -240,49 +240,39 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
240240
&self,
241241
diag: &mut Diag<'_>,
242242
lower_bound: RegionVid,
243-
) {
243+
) -> Option<()> {
244244
let mut suggestions = vec![];
245245
let tcx = self.infcx.tcx;
246246

247-
// find generic associated types in the given region 'lower_bound'
248-
let gat_id_and_generics = self
249-
.regioncx
250-
.placeholders_contained_in(lower_bound)
251-
.map(|placeholder| {
252-
if let Some(id) = placeholder.bound.kind.get_id()
253-
&& let Some(placeholder_id) = id.as_local()
254-
&& let gat_hir_id = tcx.local_def_id_to_hir_id(placeholder_id)
255-
&& let Some(generics_impl) =
256-
tcx.parent_hir_node(tcx.parent_hir_id(gat_hir_id)).generics()
257-
{
258-
Some((gat_hir_id, generics_impl))
259-
} else {
260-
None
261-
}
262-
})
263-
.collect::<Vec<_>>();
264-
debug!(?gat_id_and_generics);
265-
266247
// find higher-ranked trait bounds bounded to the generic associated types
248+
let scc = self.regioncx.constraint_sccs().scc(lower_bound);
249+
250+
let placeholder: ty::PlaceholderRegion = self.regioncx.placeholder_representative(scc)?;
251+
252+
let placeholder_id = placeholder.bound.kind.get_id()?.as_local()?;
253+
let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id);
254+
let generics_impl =
255+
self.infcx.tcx.parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id)).generics()?;
256+
267257
let mut hrtb_bounds = vec![];
268-
gat_id_and_generics.iter().flatten().for_each(|(gat_hir_id, generics)| {
269-
for pred in generics.predicates {
270-
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
271-
pred.kind
272-
else {
273-
continue;
274-
};
275-
if bound_generic_params
276-
.iter()
277-
.rfind(|bgp| tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id)
278-
.is_some()
279-
{
280-
for bound in *bounds {
281-
hrtb_bounds.push(bound);
282-
}
258+
259+
for pred in generics_impl.predicates {
260+
let BoundPredicate(WhereBoundPredicate { bound_generic_params, bounds, .. }) =
261+
pred.kind
262+
else {
263+
continue;
264+
};
265+
if bound_generic_params
266+
.iter()
267+
.rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == gat_hir_id)
268+
.is_some()
269+
{
270+
for bound in *bounds {
271+
hrtb_bounds.push(bound);
283272
}
284273
}
285-
});
274+
}
275+
286276
debug!(?hrtb_bounds);
287277

288278
hrtb_bounds.iter().for_each(|bound| {
@@ -327,6 +317,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
327317
Applicability::MaybeIncorrect,
328318
);
329319
}
320+
Some(())
330321
}
331322

332323
/// Produces nice borrowck error diagnostics for all the errors collected in `nll_errors`.

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::constraints::{ConstraintSccIndex, OutlivesConstraintSet};
2020
use crate::consumers::OutlivesConstraint;
2121
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
2222
use crate::member_constraints::MemberConstraintSet;
23-
use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
23+
use crate::region_infer::values::LivenessValues;
2424
use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
2525
use crate::ty::VarianceDiagInfo;
2626
use crate::type_check::free_region_relations::UniversalRegionRelations;
@@ -39,7 +39,6 @@ pub(crate) struct LoweredConstraints<'tcx> {
3939
pub(crate) type_tests: Vec<TypeTest<'tcx>>,
4040
pub(crate) liveness_constraints: LivenessValues,
4141
pub(crate) universe_causes: FxIndexMap<UniverseIndex, UniverseInfo<'tcx>>,
42-
pub(crate) placeholder_indices: PlaceholderIndices,
4342
}
4443

4544
impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
@@ -69,7 +68,7 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
6968
}
7069

7170
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
72-
enum PlaceholderReachability {
71+
pub(crate) enum PlaceholderReachability {
7372
/// This SCC reaches no placeholders.
7473
NoPlaceholders,
7574
/// This SCC reaches at least one placeholder.
@@ -218,6 +217,10 @@ impl RegionTracker {
218217
PlaceholderReachability::Placeholders { min_placeholder, .. } => Some(min_placeholder),
219218
}
220219
}
220+
221+
pub(crate) fn reachable_placeholders(&self) -> PlaceholderReachability {
222+
self.reachable_placeholders
223+
}
221224
}
222225
/// Pick the smallest universe index out of two, preferring
223226
/// the first argument if they are equal.
@@ -336,13 +339,12 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
336339
let (definitions, has_placeholders) = region_definitions(universal_regions, infcx);
337340

338341
let MirTypeckRegionConstraints {
339-
placeholder_indices,
340-
placeholder_index_to_region: _,
341342
liveness_constraints,
342343
mut outlives_constraints,
343344
mut member_constraints,
344345
universe_causes,
345346
type_tests,
347+
..
346348
} = constraints;
347349

348350
if let Some(guar) = universal_regions.tainted_by_errors() {
@@ -384,7 +386,6 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
384386
outlives_constraints: Frozen::freeze(outlives_constraints),
385387
liveness_constraints,
386388
universe_causes,
387-
placeholder_indices,
388389
};
389390
}
390391
debug!("Placeholders present; activating placeholder handling logic!");
@@ -427,7 +428,6 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
427428
type_tests,
428429
liveness_constraints,
429430
universe_causes,
430-
placeholder_indices,
431431
}
432432
}
433433

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 41 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
2828
use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet};
2929
use crate::dataflow::BorrowIndex;
3030
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
31-
use crate::handle_placeholders::{LoweredConstraints, RegionTracker};
31+
use crate::handle_placeholders::{LoweredConstraints, PlaceholderReachability, RegionTracker};
3232
use crate::member_constraints::{MemberConstraintSet, NllMemberConstraintIndex};
3333
use crate::polonius::LiveLoans;
3434
use crate::polonius::legacy::PoloniusOutput;
@@ -360,15 +360,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
360360
outlives_constraints,
361361
scc_annotations,
362362
type_tests,
363-
liveness_constraints,
363+
mut liveness_constraints,
364364
universe_causes,
365-
placeholder_indices,
366365
member_constraints,
367366
} = lowered_constraints;
368367

369368
debug!("universal_regions: {:#?}", universal_region_relations.universal_regions);
370369
debug!("outlives constraints: {:#?}", outlives_constraints);
371-
debug!("placeholder_indices: {:#?}", placeholder_indices);
372370
debug!("type tests: {:#?}", type_tests);
373371

374372
let constraint_graph = Frozen::freeze(outlives_constraints.graph(definitions.len()));
@@ -377,8 +375,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
377375
sccs_info(infcx, &constraint_sccs);
378376
}
379377

380-
let mut scc_values =
381-
RegionValues::new(location_map, universal_regions.len(), placeholder_indices);
378+
let mut scc_values = RegionValues::new(location_map, universal_regions.len());
382379

383380
for region in liveness_constraints.regions() {
384381
let scc = constraint_sccs.scc(region);
@@ -388,7 +385,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
388385
let member_constraints =
389386
Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r)));
390387

391-
let mut result = Self {
388+
for variable in definitions.indices() {
389+
if let NllRegionVariableOrigin::FreeRegion = definitions[variable].origin {
390+
// For each free, universally quantified region X:
391+
392+
let scc = constraint_sccs.scc(variable);
393+
394+
// Add all nodes in the CFG to liveness constraints
395+
liveness_constraints.add_all_points(variable);
396+
scc_values.add_all_points(scc);
397+
398+
// Add `end(X)` into the set for X.
399+
scc_values.add_element(scc, variable);
400+
}
401+
}
402+
403+
Self {
392404
definitions,
393405
liveness_constraints,
394406
constraints: outlives_constraints,
@@ -402,90 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
402414
scc_values,
403415
type_tests,
404416
universal_region_relations,
405-
};
406-
407-
result.init_free_and_bound_regions();
408-
409-
result
410-
}
411-
412-
/// Initializes the region variables for each universally
413-
/// quantified region (lifetime parameter). The first N variables
414-
/// always correspond to the regions appearing in the function
415-
/// signature (both named and anonymous) and where-clauses. This
416-
/// function iterates over those regions and initializes them with
417-
/// minimum values.
418-
///
419-
/// For example:
420-
/// ```
421-
/// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ }
422-
/// ```
423-
/// would initialize two variables like so:
424-
/// ```ignore (illustrative)
425-
/// R0 = { CFG, R0 } // 'a
426-
/// R1 = { CFG, R0, R1 } // 'b
427-
/// ```
428-
/// Here, R0 represents `'a`, and it contains (a) the entire CFG
429-
/// and (b) any universally quantified regions that it outlives,
430-
/// which in this case is just itself. R1 (`'b`) in contrast also
431-
/// outlives `'a` and hence contains R0 and R1.
432-
///
433-
/// This bit of logic also handles invalid universe relations
434-
/// for higher-kinded types.
435-
///
436-
/// We Walk each SCC `A` and `B` such that `A: B`
437-
/// and ensure that universe(A) can see universe(B).
438-
///
439-
/// This serves to enforce the 'empty/placeholder' hierarchy
440-
/// (described in more detail on `RegionKind`):
441-
///
442-
/// ```ignore (illustrative)
443-
/// static -----+
444-
/// | |
445-
/// empty(U0) placeholder(U1)
446-
/// | /
447-
/// empty(U1)
448-
/// ```
449-
///
450-
/// In particular, imagine we have variables R0 in U0 and R1
451-
/// created in U1, and constraints like this;
452-
///
453-
/// ```ignore (illustrative)
454-
/// R1: !1 // R1 outlives the placeholder in U1
455-
/// R1: R0 // R1 outlives R0
456-
/// ```
457-
///
458-
/// Here, we wish for R1 to be `'static`, because it
459-
/// cannot outlive `placeholder(U1)` and `empty(U0)` any other way.
460-
///
461-
/// Thanks to this loop, what happens is that the `R1: R0`
462-
/// constraint has lowered the universe of `R1` to `U0`, which in turn
463-
/// means that the `R1: !1` constraint here will cause
464-
/// `R1` to become `'static`.
465-
fn init_free_and_bound_regions(&mut self) {
466-
for variable in self.definitions.indices() {
467-
let scc = self.constraint_sccs.scc(variable);
468-
469-
match self.definitions[variable].origin {
470-
NllRegionVariableOrigin::FreeRegion => {
471-
// For each free, universally quantified region X:
472-
473-
// Add all nodes in the CFG to liveness constraints
474-
self.liveness_constraints.add_all_points(variable);
475-
self.scc_values.add_all_points(scc);
476-
477-
// Add `end(X)` into the set for X.
478-
self.scc_values.add_element(scc, variable);
479-
}
480-
481-
NllRegionVariableOrigin::Placeholder(placeholder) => {
482-
self.scc_values.add_element(scc, placeholder);
483-
}
484-
485-
NllRegionVariableOrigin::Existential { .. } => {
486-
// For existential, regions, nothing to do.
487-
}
488-
}
489417
}
490418
}
491419

@@ -542,14 +470,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
542470
self.scc_values.region_value_str(scc)
543471
}
544472

545-
pub(crate) fn placeholders_contained_in(
546-
&self,
547-
r: RegionVid,
548-
) -> impl Iterator<Item = ty::PlaceholderRegion> {
549-
let scc = self.constraint_sccs.scc(r);
550-
self.scc_values.placeholders_contained_in(scc)
551-
}
552-
553473
/// Once region solving has completed, this function will return the member constraints that
554474
/// were applied to the value of a given SCC `scc`. See `AppliedMemberConstraint`.
555475
pub(crate) fn applied_member_constraints(
@@ -901,8 +821,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
901821
//
902822
// It doesn't matter *what* universe because the promoted `T` will
903823
// always be in the root universe.
904-
if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
905-
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
824+
if let PlaceholderReachability::Placeholders { min_placeholder, .. } =
825+
self.scc_annotations[r_scc].reachable_placeholders()
826+
{
827+
debug!(
828+
"encountered placeholder in higher universe: {min_placeholder:?}, requiring 'static"
829+
);
830+
906831
let static_r = self.universal_regions().fr_static;
907832
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
908833
subject,
@@ -1792,14 +1717,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
17921717
match *element {
17931718
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
17941719
RegionElement::RootUniversalRegion(r) => r,
1795-
RegionElement::PlaceholderRegion(error_placeholder) => self
1796-
.definitions
1797-
.iter_enumerated()
1798-
.find_map(|(r, definition)| match definition.origin {
1799-
NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
1800-
_ => None,
1801-
})
1802-
.unwrap(),
18031720
}
18041721
}
18051722

@@ -2082,6 +1999,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
20821999
self.scc_annotations[scc].representative.rvid()
20832000
}
20842001

2002+
/// If the representative of an SCC is a placeholder, return
2003+
/// its originating `PlaceholderRegion`.
2004+
pub(crate) fn placeholder_representative(
2005+
&self,
2006+
scc: ConstraintSccIndex,
2007+
) -> Option<ty::PlaceholderRegion> {
2008+
if let Representative::Placeholder(r) = self.scc_annotations[scc].representative
2009+
&& let NllRegionVariableOrigin::Placeholder(p) = self.definitions[r].origin
2010+
{
2011+
Some(p)
2012+
} else {
2013+
None
2014+
}
2015+
}
2016+
20852017
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {
20862018
&self.liveness_constraints
20872019
}

compiler/rustc_borrowck/src/region_infer/opaque_types.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,17 +190,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
190190
ty::ReVar(vid) => {
191191
let scc = self.constraint_sccs.scc(vid);
192192

193-
// Special handling of higher-ranked regions.
194-
if !self.max_nameable_universe(scc).is_root() {
195-
match self.scc_values.placeholders_contained_in(scc).enumerate().last() {
196-
// If the region contains a single placeholder then they're equal.
197-
Some((0, placeholder)) => {
198-
return ty::Region::new_placeholder(tcx, placeholder);
199-
}
200-
201-
// Fallback: this will produce a cryptic error message.
202-
_ => return region,
203-
}
193+
if let Some(representative) = self.placeholder_representative(scc) {
194+
return ty::Region::new_placeholder(tcx, representative);
204195
}
205196

206197
// Find something that we can name

0 commit comments

Comments
 (0)