Skip to content

Commit 6c7f0a6

Browse files
committed
Auto merge of #125069 - amandasystems:scc-refactor, r=<try>
Extend SCC construction to enable extra functionality Do YOU feel like your SCC construction doesn't do enough? Then I have a patch for you! SCCs can now do *everything*! Well, almost. This patch has been extracted from #123720. It specifically enhances `Sccs` to allow tracking arbitrary commutative properties (think min/max mappings on nodes vs arbitrary closures) of strongly connected components, including - reachable values (max/min) - SCC-internal values (max/min) This helps with among other things universe computation. We can now identify SCC universes as a reasonably straightforward "find max/min" operation during SCC construction. This is also included in this patch. It's also more or less zero-cost; don't use the new features, don't pay for them. This commit also vastly extends the documentation of the SCCs module, which I had a very hard time following. It may or may not have gotten easier to read for someone else. I believe this logic can also be used in leak check, but haven't checked. Ha. ha. Ha.
2 parents 6be7b0c + 609a202 commit 6c7f0a6

File tree

6 files changed

+629
-342
lines changed

6 files changed

+629
-342
lines changed

compiler/rustc_borrowck/src/constraints/mod.rs

+88-16
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,99 @@
1-
use rustc_data_structures::graph::scc::Sccs;
1+
use crate::region_infer::RegionDefinition;
2+
use crate::type_check::Locations;
3+
use rustc_data_structures::graph::scc::{self, Sccs};
24
use rustc_index::{IndexSlice, IndexVec};
35
use rustc_middle::mir::ConstraintCategory;
4-
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
6+
use rustc_middle::ty::{RegionVid, UniverseIndex, VarianceDiagInfo};
57
use rustc_span::Span;
68
use std::fmt;
79
use std::ops::Index;
810

9-
use crate::type_check::Locations;
10-
1111
pub(crate) mod graph;
1212

13+
pub type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, RegionTracker>;
14+
15+
/// An annotation for region graph SCCs that tracks
16+
/// the values of its elements.
17+
#[derive(Copy, Debug, Clone)]
18+
pub struct RegionTracker {
19+
/// The largest universe of a placeholder reached from this SCC.
20+
/// This includes placeholders within this SCC.
21+
max_placeholder_universe_reached: UniverseIndex,
22+
23+
/// The smallest universe index reachable form the nodes of this SCC.
24+
min_reachable_universe: UniverseIndex,
25+
26+
/// The representative Region Variable Id for this SCC. We prefer
27+
/// placeholders over existentially quantified variables, otherwise
28+
/// it's the one with the smallest Region Variable ID.
29+
pub representative: RegionVid,
30+
31+
/// Is the current representative a placeholder?
32+
representative_is_placeholder: bool,
33+
34+
/// Is the current representative existentially quantified?
35+
representative_is_existential: bool,
36+
}
37+
38+
impl scc::Annotation for RegionTracker {
39+
fn merge_scc(mut self, mut other: Self) -> Self {
40+
// Prefer any placeholder over any existential
41+
if other.representative_is_placeholder && self.representative_is_existential {
42+
other.merge_min_max_seen(&self);
43+
return other;
44+
}
45+
46+
if self.representative_is_placeholder && other.representative_is_existential
47+
|| (self.representative <= other.representative)
48+
{
49+
self.merge_min_max_seen(&other);
50+
return self;
51+
}
52+
other.merge_min_max_seen(&self);
53+
other
54+
}
55+
56+
fn merge_reached(mut self, other: Self) -> Self {
57+
// No update to in-component values, only add seen values.
58+
self.merge_min_max_seen(&other);
59+
self
60+
}
61+
}
62+
63+
impl RegionTracker {
64+
pub fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
65+
let placeholder_universe =
66+
if definition.is_placeholder() { definition.universe } else { UniverseIndex::ROOT };
67+
68+
Self {
69+
max_placeholder_universe_reached: placeholder_universe,
70+
min_reachable_universe: definition.universe,
71+
representative: rvid,
72+
representative_is_placeholder: definition.is_placeholder(),
73+
representative_is_existential: definition.is_existential(),
74+
}
75+
}
76+
pub fn universe(self) -> UniverseIndex {
77+
self.min_reachable_universe
78+
}
79+
80+
fn merge_min_max_seen(&mut self, other: &Self) {
81+
self.max_placeholder_universe_reached = std::cmp::max(
82+
self.max_placeholder_universe_reached,
83+
other.max_placeholder_universe_reached,
84+
);
85+
86+
self.min_reachable_universe =
87+
std::cmp::min(self.min_reachable_universe, other.min_reachable_universe);
88+
}
89+
90+
/// Returns `true` if during the annotated SCC reaches a placeholder
91+
/// with a universe larger than the smallest reachable one, `false` otherwise.
92+
pub fn has_incompatible_universes(&self) -> bool {
93+
self.universe().cannot_name(self.max_placeholder_universe_reached)
94+
}
95+
}
96+
1397
/// A set of NLL region constraints. These include "outlives"
1498
/// constraints of the form `R1: R2`. Each constraint is identified by
1599
/// a unique `OutlivesConstraintIndex` and you can index into the set
@@ -45,18 +129,6 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
45129
graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars)
46130
}
47131

48-
/// Computes cycles (SCCs) in the graph of regions. In particular,
49-
/// find all regions R1, R2 such that R1: R2 and R2: R1 and group
50-
/// them into an SCC, and find the relationships between SCCs.
51-
pub(crate) fn compute_sccs(
52-
&self,
53-
constraint_graph: &graph::NormalConstraintGraph,
54-
static_region: RegionVid,
55-
) -> Sccs<RegionVid, ConstraintSccIndex> {
56-
let region_graph = &constraint_graph.region_graph(self, static_region);
57-
Sccs::new(region_graph)
58-
}
59-
60132
pub(crate) fn outlives(
61133
&self,
62134
) -> &IndexSlice<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {

0 commit comments

Comments
 (0)