Skip to content

Commit 40f3aea

Browse files
committed
Determine once and for all if there are higher-kinded concerns and nope out
This also changes how annotations for SCCs work.
1 parent a5c71c7 commit 40f3aea

File tree

6 files changed

+262
-236
lines changed

6 files changed

+262
-236
lines changed

compiler/rustc_borrowck/src/constraints/mod.rs

+25-17
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
1010
use rustc_span::Span;
1111
use tracing::{debug, instrument};
1212

13-
use crate::region_infer::{PlaceholderTracking, RegionDefinition, RegionTracker};
13+
use crate::region_infer::{PlaceholderTracking, RegionDefinition, RegionTracker, SccAnnotations};
1414
use crate::type_check::Locations;
1515
use crate::universal_regions::UniversalRegions;
1616

@@ -60,15 +60,18 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
6060
/// Computes cycles (SCCs) in the graph of regions. In particular,
6161
/// find all regions R1, R2 such that R1: R2 and R2: R1 and group
6262
/// them into an SCC, and find the relationships between SCCs.
63-
pub(crate) fn compute_sccs<A: scc::Annotation, F: Fn(RegionVid) -> A>(
63+
pub(crate) fn compute_sccs<
64+
A: scc::Annotation,
65+
AA: scc::Annotations<RegionVid, ConstraintSccIndex, A>,
66+
>(
6467
&self,
6568
static_region: RegionVid,
66-
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
67-
annotate_region: F,
68-
) -> scc::Sccs<RegionVid, ConstraintSccIndex, A> {
69-
let constraint_graph = self.graph(definitions.len());
69+
num_region_vars: usize,
70+
annotations: &mut AA,
71+
) -> scc::Sccs<RegionVid, ConstraintSccIndex> {
72+
let constraint_graph = self.graph(num_region_vars);
7073
let region_graph = &constraint_graph.region_graph(self, static_region);
71-
scc::Sccs::new_with_annotation(&region_graph, annotate_region)
74+
scc::Sccs::new_with_annotation(&region_graph, annotations)
7275
}
7376

7477
/// There is a placeholder violation; add a requirement
@@ -127,20 +130,20 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
127130
/// Every constraint added by this method is an
128131
/// internal `IllegalUniverse` constraint.
129132
#[instrument(skip(self, universal_regions, definitions))]
130-
pub(crate) fn add_outlives_static(
133+
pub(crate) fn add_outlives_static<'d>(
131134
&mut self,
132135
universal_regions: &UniversalRegions<'tcx>,
133-
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
134-
) -> scc::Sccs<RegionVid, ConstraintSccIndex, PlaceholderTracking> {
136+
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
137+
) -> (scc::Sccs<RegionVid, ConstraintSccIndex>, PlaceholderTracking) {
135138
let fr_static = universal_regions.fr_static;
136-
let new_tracker = |r| PlaceholderTracking::On(RegionTracker::new(r, &definitions[r]));
137-
138-
let sccs = self.compute_sccs(fr_static, definitions, new_tracker);
139+
let mut annotations = SccAnnotations::init(definitions);
140+
let sccs = self.compute_sccs(fr_static, definitions.len(), &mut annotations);
139141

140142
// Is this SCC already outliving static directly or transitively?
141143
let mut outlives_static = FxHashSet::default();
142144

143-
for (scc, annotation) in sccs.all_annotations() {
145+
for scc in sccs.all_sccs() {
146+
let annotation: RegionTracker = annotations.scc_to_annotation[scc];
144147
if scc == sccs.scc(fr_static) {
145148
// No use adding 'static: 'static.
146149
continue;
@@ -178,7 +181,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
178181

179182
// The second kind of violation: a placeholder reaching another placeholder.
180183
for (scc, rvid) in placeholders_and_sccs {
181-
let annotation = sccs.annotation(scc);
184+
let annotation = annotations.scc_to_annotation[scc];
182185

183186
if sccs.scc(fr_static) == scc || outlives_static.contains(&scc) {
184187
debug!("{:?} already outlives (or is) static", annotation.representative_rvid());
@@ -201,11 +204,16 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
201204

202205
if !outlives_static.is_empty() {
203206
debug!("The following SCCs had :'static constraints added: {:?}", outlives_static);
207+
let mut annotations = SccAnnotations::init(definitions);
208+
204209
// We changed the constraint set and so must recompute SCCs.
205-
self.compute_sccs(fr_static, definitions, new_tracker)
210+
(
211+
self.compute_sccs(fr_static, definitions.len(), &mut annotations),
212+
PlaceholderTracking::On(annotations.scc_to_annotation),
213+
)
206214
} else {
207215
// If we didn't add any back-edges; no more work needs doing
208-
sccs
216+
(sccs, PlaceholderTracking::On(annotations.scc_to_annotation))
209217
}
210218
}
211219
}

compiler/rustc_borrowck/src/nll.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
162162
universe_causes,
163163
type_tests,
164164
liveness_constraints,
165-
elements.clone(),
165+
elements,
166166
);
167167

168168
// If requested: dump NLL facts, and run legacy polonius analysis.

compiler/rustc_borrowck/src/region_infer/mod.rs

+75-90
Original file line numberDiff line numberDiff line change
@@ -46,89 +46,53 @@ mod reverse_sccs;
4646

4747
pub(crate) mod values;
4848

49-
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, PlaceholderTracking>;
50-
51-
#[derive(Copy, Clone, Debug)]
52-
pub enum PlaceholderTracking {
53-
Off(Representative),
54-
On(RegionTracker),
49+
pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
50+
pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
51+
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
5552
}
5653

57-
impl scc::Annotation for PlaceholderTracking {
58-
fn merge_scc(self, other: Self) -> Self {
59-
use PlaceholderTracking::*;
60-
61-
match (self, other) {
62-
(Off(this), Off(that)) => Off(this.merge_scc(that)),
63-
(On(this), On(that)) => On(this.merge_scc(that)),
64-
_ => unreachable!(),
65-
}
66-
}
67-
68-
fn merge_reached(self, other: Self) -> Self {
69-
use PlaceholderTracking::*;
70-
71-
match (self, other) {
72-
(Off(this), Off(that)) => Off(this.merge_reached(that)),
73-
(On(this), On(that)) => On(this.merge_reached(that)),
74-
_ => unreachable!(),
75-
}
54+
impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
55+
pub(crate) fn init(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
56+
Self { scc_to_annotation: IndexVec::new(), definitions }
7657
}
7758
}
7859

79-
impl PlaceholderTracking {
80-
pub(crate) fn representative_rvid(&self) -> RegionVid {
81-
match self {
82-
PlaceholderTracking::Off(r) => r.rvid(),
83-
PlaceholderTracking::On(region_tracker) => region_tracker.representative_rvid(),
84-
}
85-
}
86-
87-
pub(crate) fn reaches_other_placeholder(&self, other: RegionVid) -> Option<RegionVid> {
88-
match self {
89-
PlaceholderTracking::Off(_) => None,
90-
PlaceholderTracking::On(region_tracker) => {
91-
region_tracker.reaches_other_placeholder(other)
92-
}
93-
}
60+
impl scc::Annotations<RegionVid, ConstraintSccIndex, RegionTracker>
61+
for SccAnnotations<'_, '_, RegionTracker>
62+
{
63+
fn new(&self, element: RegionVid) -> RegionTracker {
64+
RegionTracker::new(element, &self.definitions[element])
9465
}
9566

96-
pub(crate) fn universe_violation(&self) -> Option<RegionVid> {
97-
match self {
98-
PlaceholderTracking::Off(_) => None,
99-
PlaceholderTracking::On(region_tracker) => region_tracker.universe_violation(),
100-
}
67+
fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
68+
let idx = self.scc_to_annotation.push(annotation);
69+
assert!(idx == scc);
10170
}
71+
}
10272

103-
fn min_universe(&self) -> UniverseIndex {
104-
match self {
105-
PlaceholderTracking::Off(_) => UniverseIndex::ROOT, // Not technically correct?
106-
PlaceholderTracking::On(region_tracker) => region_tracker.min_universe(),
107-
}
73+
impl scc::Annotations<RegionVid, ConstraintSccIndex, Representative>
74+
for SccAnnotations<'_, '_, Representative>
75+
{
76+
fn new(&self, element: RegionVid) -> Representative {
77+
Representative::new(element, self.definitions)
10878
}
10979

110-
fn universe_compatible_with(&self, other: PlaceholderTracking) -> bool {
111-
use PlaceholderTracking::*;
112-
match (self, other) {
113-
(Off(_), Off(_)) => true, // Not technically correct?
114-
(On(this), On(that)) => this.universe_compatible_with(that),
115-
_ => unreachable!(),
116-
}
80+
fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: Representative) {
81+
let idx = self.scc_to_annotation.push(annotation);
82+
assert!(idx == scc);
11783
}
84+
}
11885

119-
fn placeholder_representative(&self) -> Option<RegionVid> {
120-
match self {
121-
PlaceholderTracking::Off(_) => None,
122-
PlaceholderTracking::On(region_tracker) => region_tracker.placeholder_representative(),
123-
}
124-
}
86+
pub(crate) enum PlaceholderTracking {
87+
Off(IndexVec<ConstraintSccIndex, Representative>),
88+
On(IndexVec<ConstraintSccIndex, RegionTracker>),
12589
}
12690

12791
/// The representative region variable for an SCC, tagged by its origin.
12892
/// We prefer placeholders over existentially quantified variables, otherwise
12993
/// it's the one with the smallest Region Variable ID.
13094
#[derive(Copy, Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
131-
pub enum Representative {
95+
pub(crate) enum Representative {
13296
FreeRegion(RegionVid),
13397
Placeholder(RegionVid),
13498
Existential(RegionVid),
@@ -217,7 +181,7 @@ impl PlaceholderReachability {
217181
/// An annotation for region graph SCCs that tracks
218182
/// the values of its elements.
219183
#[derive(Copy, Debug, Clone)]
220-
pub struct RegionTracker {
184+
pub(crate) struct RegionTracker {
221185
/// The representative Region Variable Id for this SCC.
222186
representative: Representative,
223187

@@ -379,7 +343,9 @@ pub struct RegionInferenceContext<'tcx> {
379343
/// The SCC computed from `constraints` and the constraint
380344
/// graph. We have an edge from SCC A to SCC B if `A: B`. Used to
381345
/// compute the values of each region.
382-
constraint_sccs: ConstraintSccs,
346+
constraint_sccs: Sccs<RegionVid, ConstraintSccIndex>,
347+
348+
scc_annotations: PlaceholderTracking,
383349

384350
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
385351
/// `B: A`. This is used to compute the universal regions that are required
@@ -541,9 +507,9 @@ pub(crate) enum ExtraConstraintInfo {
541507
}
542508

543509
#[instrument(skip(infcx, sccs), level = "debug")]
544-
fn sccs_info<'tcx, A: scc::Annotation>(
510+
fn sccs_info<'tcx>(
545511
infcx: &BorrowckInferCtxt<'tcx>,
546-
sccs: &scc::Sccs<RegionVid, ConstraintSccIndex, A>,
512+
sccs: &scc::Sccs<RegionVid, ConstraintSccIndex>,
547513
) {
548514
use crate::renumber::RegionCtxt;
549515

@@ -624,7 +590,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
624590
universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
625591
type_tests: Vec<TypeTest<'tcx>>,
626592
mut liveness_constraints: LivenessValues,
627-
elements: &Rc<DenseLocationMap>,
593+
elements: Rc<DenseLocationMap>,
628594
) -> Self {
629595
debug!("universal_regions: {:#?}", universal_regions);
630596
debug!("outlives constraints: {:#?}", outlives_constraints);
@@ -650,14 +616,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
650616
(definitions, has_placeholders)
651617
};
652618

653-
let constraint_sccs = if has_placeholders {
619+
let (constraint_sccs, scc_annotations) = if has_placeholders {
654620
debug!("Placeholders present; activating placeholder handling logic!");
655621
outlives_constraints.add_outlives_static(&universal_regions, &definitions)
656622
} else {
657623
debug!("No placeholders in MIR body; disabling their validation.");
658-
outlives_constraints.compute_sccs(universal_regions.fr_static, &definitions, |r| {
659-
PlaceholderTracking::Off(Representative::new(r, &definitions))
660-
})
624+
let mut annotator = SccAnnotations::init(&definitions);
625+
let sccs = outlives_constraints.compute_sccs(
626+
universal_regions.fr_static,
627+
definitions.len(),
628+
&mut annotator,
629+
);
630+
(sccs, PlaceholderTracking::Off(annotator.scc_to_annotation))
661631
};
662632
let constraints = Frozen::freeze(outlives_constraints);
663633
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
@@ -707,6 +677,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
707677
type_tests,
708678
universal_regions,
709679
universal_region_relations,
680+
scc_annotations,
710681
}
711682
}
712683

@@ -932,8 +903,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
932903

933904
// If the member region lives in a higher universe, we currently choose
934905
// the most conservative option by leaving it unchanged.
935-
936-
if !self.constraint_sccs().annotation(scc).min_universe().is_root() {
906+
if !self.scc_universe(scc).is_root() {
937907
return;
938908
}
939909

@@ -1005,9 +975,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
1005975
/// in `scc_a`. Used during constraint propagation, and only once
1006976
/// the value of `scc_b` has been computed.
1007977
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
1008-
self.constraint_sccs()
1009-
.annotation(scc_a)
1010-
.universe_compatible_with(self.constraint_sccs().annotation(scc_b))
978+
match &self.scc_annotations {
979+
// This isn't technically true but seems to work.
980+
PlaceholderTracking::Off(_) => true,
981+
PlaceholderTracking::On(annotations) => {
982+
annotations[scc_a].universe_compatible_with(annotations[scc_b])
983+
}
984+
}
1011985
}
1012986

1013987
/// Once regions have been propagated, this method is used to see
@@ -1115,7 +1089,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11151089
"lower_bound = {:?} r_scc={:?} universe={:?}",
11161090
lower_bound,
11171091
r_scc,
1118-
self.constraint_sccs.annotation(r_scc).min_universe()
1092+
self.scc_universe(r_scc)
11191093
);
11201094

11211095
// If the type test requires that `T: 'a` where `'a` is a
@@ -1125,7 +1099,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11251099
// It doesn't matter *what* universe because the promoted `T` will
11261100
// always be in the root universe.
11271101

1128-
if let Some(p) = self.constraint_sccs.annotation(r_scc).placeholder_representative() {
1102+
if let Some(p) = self.placeholder_representative(r_scc) {
11291103
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
11301104
let static_r = self.universal_regions.fr_static;
11311105
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
@@ -1633,7 +1607,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16331607
/// The minimum universe of any variable reachable from this
16341608
/// SCC, inside or outside of it.
16351609
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
1636-
self.constraint_sccs().annotation(scc).min_universe()
1610+
match &self.scc_annotations {
1611+
PlaceholderTracking::Off(_) => UniverseIndex::ROOT, // Not technically correct?
1612+
PlaceholderTracking::On(annotations) => annotations[scc].min_universe(),
1613+
}
16371614
}
16381615
/// Checks the final value for the free region `fr` to see if it
16391616
/// grew too large. In particular, examine what `end(X)` points
@@ -2303,7 +2280,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23032280
/// This can be used to quickly under-approximate the regions which are equal to each other
23042281
/// and their relative orderings.
23052282
// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
2306-
pub fn constraint_sccs(&self) -> &ConstraintSccs {
2283+
pub fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> {
23072284
&self.constraint_sccs
23082285
}
23092286

@@ -2343,7 +2320,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23432320
/// they *must* be equal (though not having the same repr does not
23442321
/// mean they are unequal).
23452322
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
2346-
self.constraint_sccs.annotation(scc).representative_rvid()
2323+
match &self.scc_annotations {
2324+
PlaceholderTracking::Off(annotations) => annotations[scc].rvid(),
2325+
PlaceholderTracking::On(annotations) => annotations[scc].representative_rvid(),
2326+
}
23472327
}
23482328

23492329
/// Returns true if `r` is `'static`.
@@ -2357,13 +2337,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
23572337
&self,
23582338
scc: ConstraintSccIndex,
23592339
) -> Option<PlaceholderRegion> {
2360-
if let Some(representative) =
2361-
self.constraint_sccs.annotation(scc).placeholder_representative()
2362-
&& let NllRegionVariableOrigin::Placeholder(p) = self.definitions[representative].origin
2363-
{
2364-
Some(p)
2365-
} else {
2366-
None
2340+
match &self.scc_annotations {
2341+
PlaceholderTracking::Off(_) => None,
2342+
PlaceholderTracking::On(annotations) => {
2343+
if let Some(representative) = annotations[scc].placeholder_representative()
2344+
&& let NllRegionVariableOrigin::Placeholder(p) =
2345+
self.definitions[representative].origin
2346+
{
2347+
Some(p)
2348+
} else {
2349+
None
2350+
}
2351+
}
23672352
}
23682353
}
23692354
}

0 commit comments

Comments
 (0)