Skip to content

Commit b1e4ca5

Browse files
committed
Use an enum for SCC representatives, plus other code review
1 parent dbc6b67 commit b1e4ca5

File tree

4 files changed

+109
-104
lines changed

4 files changed

+109
-104
lines changed

compiler/rustc_borrowck/src/eliminate_placeholders.rs

Lines changed: 56 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! This logic is provisional and should be removed once the trait
66
//! solver can handle this kind of constraint.
77
use rustc_data_structures::frozen::Frozen;
8-
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
8+
use rustc_data_structures::fx::FxIndexMap;
99
use rustc_data_structures::graph::scc;
1010
use rustc_data_structures::graph::scc::Sccs;
1111
use rustc_index::IndexVec;
@@ -18,7 +18,7 @@ use crate::consumers::OutlivesConstraint;
1818
use crate::diagnostics::UniverseInfo;
1919
use crate::member_constraints::MemberConstraintSet;
2020
use crate::region_infer::values::{LivenessValues, PlaceholderIndices};
21-
use crate::region_infer::{ConstraintSccs, RegionDefinition, TypeTest};
21+
use crate::region_infer::{ConstraintSccs, RegionDefinition, Representative, TypeTest};
2222
use crate::ty::VarianceDiagInfo;
2323
use crate::type_check::free_region_relations::UniversalRegionRelations;
2424
use crate::type_check::{Locations, MirTypeckRegionConstraints};
@@ -32,7 +32,7 @@ pub(crate) struct LoweredConstraints<'tcx> {
3232
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
3333
pub(crate) scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
3434
pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
35-
pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>,
35+
pub(crate) outlives_constraints: Frozen<OutlivesConstraintSet<'tcx>>,
3636
pub(crate) type_tests: Vec<TypeTest<'tcx>>,
3737
pub(crate) liveness_constraints: LivenessValues,
3838
pub(crate) universe_causes: FxIndexMap<UniverseIndex, UniverseInfo<'tcx>>,
@@ -73,45 +73,35 @@ pub(crate) struct RegionTracker {
7373
/// This includes placeholders within this SCC.
7474
max_placeholder_universe_reached: UniverseIndex,
7575

76-
/// The smallest universe index reachable form the nodes of this SCC.
77-
min_reachable_universe: UniverseIndex,
76+
/// The smallest universe nameable from this SCC.
77+
/// It is the smallest of all the largest nameable universes
78+
/// of any region reachable from it.
79+
max_nameable_universe: UniverseIndex,
7880

79-
/// The representative Region Variable Id for this SCC. We prefer
80-
/// placeholders over existentially quantified variables, otherwise
81-
/// it's the one with the smallest Region Variable ID.
82-
pub(crate) representative: RegionVid,
83-
84-
/// Is the current representative a placeholder?
85-
representative_is_placeholder: bool,
86-
87-
/// Is the current representative existentially quantified?
88-
representative_is_existential: bool,
81+
/// The representative Region Variable Id for this SCC.
82+
pub(crate) representative: Representative,
8983
}
9084

9185
impl RegionTracker {
9286
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
93-
let (representative_is_placeholder, representative_is_existential) = match definition.origin
94-
{
95-
NllRegionVariableOrigin::FreeRegion => (false, false),
96-
NllRegionVariableOrigin::Placeholder(_) => (true, false),
97-
NllRegionVariableOrigin::Existential { .. } => (false, true),
98-
};
99-
10087
let placeholder_universe =
101-
if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT };
88+
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
89+
definition.universe
90+
} else {
91+
UniverseIndex::ROOT
92+
};
10293

10394
Self {
10495
max_placeholder_universe_reached: placeholder_universe,
105-
min_reachable_universe: definition.universe,
106-
representative: rvid,
107-
representative_is_placeholder,
108-
representative_is_existential,
96+
max_nameable_universe: definition.universe,
97+
representative: Representative::new(rvid, definition),
10998
}
11099
}
111100

112-
/// The smallest-indexed universe reachable from and/or in this SCC.
113-
pub(crate) fn min_universe(self) -> UniverseIndex {
114-
self.min_reachable_universe
101+
/// The largest universe this SCC can name. It's the smallest
102+
/// largest nameable uninverse of any reachable region.
103+
pub(crate) fn max_nameable_universe(self) -> UniverseIndex {
104+
self.max_nameable_universe
115105
}
116106

117107
fn merge_min_max_seen(&mut self, other: &Self) {
@@ -120,40 +110,28 @@ impl RegionTracker {
120110
other.max_placeholder_universe_reached,
121111
);
122112

123-
self.min_reachable_universe =
124-
std::cmp::min(self.min_reachable_universe, other.min_reachable_universe);
113+
self.max_nameable_universe =
114+
std::cmp::min(self.max_nameable_universe, other.max_nameable_universe);
125115
}
126116

127117
/// Returns `true` if during the annotated SCC reaches a placeholder
128118
/// with a universe larger than the smallest reachable one, `false` otherwise.
129119
pub(crate) fn has_incompatible_universes(&self) -> bool {
130-
self.min_universe().cannot_name(self.max_placeholder_universe_reached)
120+
self.max_nameable_universe().cannot_name(self.max_placeholder_universe_reached)
131121
}
132122

133-
/// Determine if the tracked universes of the two SCCs
134-
/// are compatible.
123+
/// Determine if the tracked universes of the two SCCs are compatible.
135124
pub(crate) fn universe_compatible_with(&self, other: Self) -> bool {
136-
self.min_universe().can_name(other.min_universe())
137-
|| self.min_universe().can_name(other.max_placeholder_universe_reached)
125+
self.max_nameable_universe().can_name(other.max_nameable_universe())
126+
|| self.max_nameable_universe().can_name(other.max_placeholder_universe_reached)
138127
}
139128
}
140129

141130
impl scc::Annotation for RegionTracker {
142-
fn merge_scc(mut self, mut other: Self) -> Self {
143-
// Prefer any placeholder over any existential
144-
if other.representative_is_placeholder && self.representative_is_existential {
145-
other.merge_min_max_seen(&self);
146-
return other;
147-
}
148-
149-
if self.representative_is_placeholder && other.representative_is_existential
150-
|| (self.representative <= other.representative)
151-
{
152-
self.merge_min_max_seen(&other);
153-
return self;
154-
}
155-
other.merge_min_max_seen(&self);
156-
other
131+
fn merge_scc(mut self, other: Self) -> Self {
132+
self.representative = self.representative.merge_scc(other.representative);
133+
self.merge_min_max_seen(&other);
134+
self
157135
}
158136

159137
fn merge_reached(mut self, other: Self) -> Self {
@@ -164,7 +142,7 @@ impl scc::Annotation for RegionTracker {
164142
}
165143

166144
/// Determines if the region variable definitions contain
167-
/// placeholers, and compute them for later use.
145+
/// placeholders, and compute them for later use.
168146
fn region_definitions<'tcx>(
169147
universal_regions: &UniversalRegions<'tcx>,
170148
infcx: &BorrowckInferCtxt<'tcx>,
@@ -190,7 +168,7 @@ fn region_definitions<'tcx>(
190168
(Frozen::freeze(definitions), has_placeholders)
191169
}
192170

193-
/// This method handles Universe errors by rewriting the constraint
171+
/// This method handles placeholders by rewriting the constraint
194172
/// graph. For each strongly connected component in the constraint
195173
/// graph such that there is a series of constraints
196174
/// A: B: C: ... : X where
@@ -200,19 +178,9 @@ fn region_definitions<'tcx>(
200178
/// eventually go away.
201179
///
202180
/// For a more precise definition, see the documentation for
203-
/// [`RegionTracker`] and its methods!.
204-
///
205-
/// Since universes can also be involved in errors (if one placeholder
206-
/// transitively outlives another), this function also flags those.
207-
///
208-
/// Additionally, it similarly rewrites type-tests.
209-
///
210-
/// This edge case used to be handled during constraint propagation
211-
/// by iterating over the strongly connected components in the constraint
212-
/// graph while maintaining a set of bookkeeping mappings similar
213-
/// to what is stored in `RegionTracker` and manually adding 'sttaic as
214-
/// needed.
181+
/// [`RegionTracker`] and its methods!
215182
///
183+
/// This edge case used to be handled during constraint propagation.
216184
/// It was rewritten as part of the Polonius project with the goal of moving
217185
/// higher-kindedness concerns out of the path of the borrow checker,
218186
/// for two reasons:
@@ -267,36 +235,37 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
267235
)
268236
};
269237

238+
let mut scc_annotations = SccAnnotations::init(&definitions);
239+
let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
240+
270241
// This code structure is a bit convoluted because it allows for a planned
271242
// future change where the early return here has a different type of annotation
272243
// that does much less work.
273244
if !has_placeholders {
274245
debug!("No placeholder regions found; skipping rewriting logic!");
275-
let mut scc_annotations = SccAnnotations::init(&definitions);
276-
let constraint_sccs = compute_sccs(&outlives_constraints, &mut scc_annotations);
277246

278247
return LoweredConstraints {
279248
type_tests,
280249
member_constraints,
281250
constraint_sccs,
282251
scc_annotations: scc_annotations.scc_to_annotation,
283252
definitions,
284-
outlives_constraints,
253+
outlives_constraints: Frozen::freeze(outlives_constraints),
285254
liveness_constraints,
286255
universe_causes,
287256
placeholder_indices,
288257
};
289258
}
290259
debug!("Placeholders present; activating placeholder handling logic!");
291260

292-
let mut annotations = SccAnnotations::init(&definitions);
293-
let sccs = compute_sccs(&outlives_constraints, &mut annotations);
294-
295-
let outlives_static =
296-
rewrite_outlives(&sccs, &annotations, fr_static, &mut outlives_constraints);
261+
let added_constraints = rewrite_placeholder_outlives(
262+
&constraint_sccs,
263+
&scc_annotations,
264+
fr_static,
265+
&mut outlives_constraints,
266+
);
297267

298-
let (sccs, scc_annotations) = if !outlives_static.is_empty() {
299-
debug!("The following SCCs had :'static constraints added: {:?}", outlives_static);
268+
let (constraint_sccs, scc_annotations) = if added_constraints {
300269
let mut annotations = SccAnnotations::init(&definitions);
301270

302271
// We changed the constraint set and so must recompute SCCs.
@@ -307,31 +276,31 @@ pub(crate) fn rewrite_higher_kinded_outlives_as_constraints<'tcx>(
307276
} else {
308277
// If we didn't add any back-edges; no more work needs doing
309278
debug!("No constraints rewritten!");
310-
(sccs, annotations.scc_to_annotation)
279+
(constraint_sccs, scc_annotations.scc_to_annotation)
311280
};
312281

313282
LoweredConstraints {
314-
constraint_sccs: sccs,
283+
constraint_sccs,
315284
definitions,
316285
scc_annotations,
317286
member_constraints,
318-
outlives_constraints,
287+
outlives_constraints: Frozen::freeze(outlives_constraints),
319288
type_tests,
320289
liveness_constraints,
321290
universe_causes,
322291
placeholder_indices,
323292
}
324293
}
325294

326-
fn rewrite_outlives<'tcx>(
295+
fn rewrite_placeholder_outlives<'tcx>(
327296
sccs: &Sccs<RegionVid, ConstraintSccIndex>,
328297
annotations: &SccAnnotations<'_, '_, RegionTracker>,
329298
fr_static: RegionVid,
330299
outlives_constraints: &mut OutlivesConstraintSet<'tcx>,
331-
) -> FxHashSet<ConstraintSccIndex> {
332-
// Changed to `true` if we added any constraints to `self` and need to
300+
) -> bool {
301+
// Changed to `true` if we added any constraints and need to
333302
// recompute SCCs.
334-
let mut outlives_static = FxHashSet::default();
303+
let mut added_constraints = false;
335304

336305
let annotations = &annotations.scc_to_annotation;
337306

@@ -354,9 +323,8 @@ fn rewrite_outlives<'tcx>(
354323
// needed for correctness, since an SCC upstream of another with
355324
// a universe violation will "infect" its downstream SCCs to also
356325
// outlive static.
357-
outlives_static.insert(scc);
358326
let scc_representative_outlives_static = OutlivesConstraint {
359-
sup: annotation.representative,
327+
sup: annotation.representative.rvid(),
360328
sub: fr_static,
361329
category: ConstraintCategory::IllegalUniverse,
362330
locations: Locations::All(rustc_span::DUMMY_SP),
@@ -365,7 +333,9 @@ fn rewrite_outlives<'tcx>(
365333
from_closure: false,
366334
};
367335
outlives_constraints.push(scc_representative_outlives_static);
336+
added_constraints = true;
337+
debug!("Added {:?}: 'static!", annotation.representative.rvid());
368338
}
369339
}
370-
outlives_static
340+
added_constraints
371341
}

compiler/rustc_borrowck/src/region_infer/dump_mir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
4646
"| {r:rw$?} | {ui:4?} | {v}",
4747
r = region,
4848
rw = REGION_WIDTH,
49-
ui = self.region_universe(region),
49+
ui = self.max_nameable_universe(self.constraint_sccs.scc(region)),
5050
v = self.region_value_str(region),
5151
)?;
5252
}

0 commit comments

Comments
 (0)