Skip to content

Commit 1805d8a

Browse files
committed
Auto merge of rust-lang#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 rust-lang#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 a5c37ee + c510e73 commit 1805d8a

File tree

6 files changed

+624
-342
lines changed

6 files changed

+624
-342
lines changed

compiler/rustc_borrowck/src/constraints/mod.rs

+95-16
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,106 @@
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 (representative_is_placeholder, representative_is_existential) = match definition.origin
66+
{
67+
rustc_infer::infer::NllRegionVariableOrigin::FreeRegion => (false, false),
68+
rustc_infer::infer::NllRegionVariableOrigin::Placeholder(_) => (true, false),
69+
rustc_infer::infer::NllRegionVariableOrigin::Existential { .. } => (false, true),
70+
};
71+
72+
let placeholder_universe =
73+
if representative_is_placeholder { definition.universe } else { UniverseIndex::ROOT };
74+
75+
Self {
76+
max_placeholder_universe_reached: placeholder_universe,
77+
min_reachable_universe: definition.universe,
78+
representative: rvid,
79+
representative_is_placeholder,
80+
representative_is_existential,
81+
}
82+
}
83+
pub fn universe(self) -> UniverseIndex {
84+
self.min_reachable_universe
85+
}
86+
87+
fn merge_min_max_seen(&mut self, other: &Self) {
88+
self.max_placeholder_universe_reached = std::cmp::max(
89+
self.max_placeholder_universe_reached,
90+
other.max_placeholder_universe_reached,
91+
);
92+
93+
self.min_reachable_universe =
94+
std::cmp::min(self.min_reachable_universe, other.min_reachable_universe);
95+
}
96+
97+
/// Returns `true` if during the annotated SCC reaches a placeholder
98+
/// with a universe larger than the smallest reachable one, `false` otherwise.
99+
pub fn has_incompatible_universes(&self) -> bool {
100+
self.universe().cannot_name(self.max_placeholder_universe_reached)
101+
}
102+
}
103+
13104
/// A set of NLL region constraints. These include "outlives"
14105
/// constraints of the form `R1: R2`. Each constraint is identified by
15106
/// a unique `OutlivesConstraintIndex` and you can index into the set
@@ -45,18 +136,6 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
45136
graph::ConstraintGraph::new(graph::Reverse, self, num_region_vars)
46137
}
47138

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-
60139
pub(crate) fn outlives(
61140
&self,
62141
) -> &IndexSlice<OutlivesConstraintIndex, OutlivesConstraint<'tcx>> {

0 commit comments

Comments
 (0)