Skip to content

Commit 3989564

Browse files
committed
Borrowck: Simplify SCC annotation computation, placeholder rewriting
This change backports some changes from the now abandoned rust-lang#142623. Notably, it simplifies the `PlaceholderReachability` `enum` by replacing the case when no placeholders were reached with a standard `Option::None`. It also rewrites the API for `scc::Annotations` to be update-mut rather than a more Functional programming style. This snowed some slight performance impact in early tests of the PR and definitely makes the implementation simpler.
1 parent 5e33838 commit 3989564

3 files changed

Lines changed: 55 additions & 103 deletions

File tree

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 38 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -62,65 +62,31 @@ impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
6262
}
6363

6464
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
65-
enum PlaceholderReachability {
66-
/// This SCC reaches no placeholders.
67-
NoPlaceholders,
68-
/// This SCC reaches at least one placeholder.
69-
Placeholders {
70-
/// The largest-universed placeholder we can reach
71-
max_universe: (UniverseIndex, RegionVid),
72-
73-
/// The placeholder with the smallest ID
74-
min_placeholder: RegionVid,
75-
76-
/// The placeholder with the largest ID
77-
max_placeholder: RegionVid,
78-
},
65+
struct PlaceholderReachability {
66+
/// The largest-universed placeholder we can reach
67+
max_universe: (UniverseIndex, RegionVid),
68+
69+
/// The placeholder with the smallest ID
70+
min_placeholder: RegionVid,
71+
72+
/// The placeholder with the largest ID
73+
max_placeholder: RegionVid,
7974
}
8075

8176
impl PlaceholderReachability {
8277
/// Merge the reachable placeholders of two graph components.
83-
fn merge(self, other: PlaceholderReachability) -> PlaceholderReachability {
84-
use PlaceholderReachability::*;
85-
match (self, other) {
86-
(NoPlaceholders, NoPlaceholders) => NoPlaceholders,
87-
(NoPlaceholders, p @ Placeholders { .. })
88-
| (p @ Placeholders { .. }, NoPlaceholders) => p,
89-
(
90-
Placeholders {
91-
min_placeholder: min_pl,
92-
max_placeholder: max_pl,
93-
max_universe: max_u,
94-
},
95-
Placeholders { min_placeholder, max_placeholder, max_universe },
96-
) => Placeholders {
97-
min_placeholder: min_pl.min(min_placeholder),
98-
max_placeholder: max_pl.max(max_placeholder),
99-
max_universe: max_u.max(max_universe),
100-
},
101-
}
102-
}
103-
104-
fn max_universe(&self) -> Option<(UniverseIndex, RegionVid)> {
105-
match self {
106-
Self::NoPlaceholders => None,
107-
Self::Placeholders { max_universe, .. } => Some(*max_universe),
108-
}
109-
}
110-
111-
/// If we have reached placeholders, determine if they can
112-
/// be named from this universe.
113-
fn can_be_named_by(&self, from: UniverseIndex) -> bool {
114-
self.max_universe()
115-
.is_none_or(|(max_placeholder_universe, _)| from.can_name(max_placeholder_universe))
78+
fn merge(&mut self, other: &Self) {
79+
self.max_universe = self.max_universe.max(other.max_universe);
80+
self.min_placeholder = self.min_placeholder.min(other.min_placeholder);
81+
self.max_placeholder = self.max_placeholder.max(other.max_placeholder);
11682
}
11783
}
11884

11985
/// An annotation for region graph SCCs that tracks
12086
/// the values of its elements. This annotates a single SCC.
12187
#[derive(Copy, Debug, Clone)]
12288
pub(crate) struct RegionTracker {
123-
reachable_placeholders: PlaceholderReachability,
89+
reachable_placeholders: Option<PlaceholderReachability>,
12490

12591
/// The largest universe nameable from this SCC.
12692
/// It is the smallest nameable universes of all
@@ -135,13 +101,13 @@ impl RegionTracker {
135101
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
136102
let reachable_placeholders =
137103
if matches!(definition.origin, NllRegionVariableOrigin::Placeholder(_)) {
138-
PlaceholderReachability::Placeholders {
104+
Some(PlaceholderReachability {
139105
max_universe: (definition.universe, rvid),
140106
min_placeholder: rvid,
141107
max_placeholder: rvid,
142-
}
108+
})
143109
} else {
144-
PlaceholderReachability::NoPlaceholders
110+
None
145111
};
146112

147113
Self {
@@ -159,11 +125,13 @@ impl RegionTracker {
159125
}
160126

161127
pub(crate) fn max_placeholder_universe_reached(self) -> UniverseIndex {
162-
if let Some((universe, _)) = self.reachable_placeholders.max_universe() {
163-
universe
164-
} else {
165-
UniverseIndex::ROOT
166-
}
128+
self.reachable_placeholders.map(|pls| pls.max_universe.0).unwrap_or(UniverseIndex::ROOT)
129+
}
130+
131+
/// Can all reachable placeholders be named from `from`?
132+
/// True vacuously in case no placeholders were reached.
133+
fn placeholders_can_be_named_by(&self, from: UniverseIndex) -> bool {
134+
self.reachable_placeholders.is_none_or(|pls| from.can_name(pls.max_universe.0))
167135
}
168136

169137
/// Determine if the tracked universes of the two SCCs are compatible.
@@ -172,34 +140,31 @@ impl RegionTracker {
172140
// of `other`. This only exists to avoid errors in case that scc already
173141
// depends on a placeholder it cannot name itself.
174142
self.max_nameable_universe().can_name(other.max_nameable_universe())
175-
|| other.reachable_placeholders.can_be_named_by(self.max_nameable_universe())
143+
|| other.placeholders_can_be_named_by(self.max_nameable_universe())
176144
}
177145

178146
/// If this SCC reaches a placeholder it can't name, return it.
179147
fn unnameable_placeholder(&self) -> Option<(UniverseIndex, RegionVid)> {
180-
self.reachable_placeholders.max_universe().filter(|&(placeholder_universe, _)| {
181-
!self.max_nameable_universe().can_name(placeholder_universe)
182-
})
148+
self.reachable_placeholders
149+
.filter(|pls| !self.max_nameable_universe().can_name(pls.max_universe.0))
150+
.map(|pls| pls.max_universe)
183151
}
184152
}
185153

186154
impl scc::Annotation for RegionTracker {
187-
fn merge_scc(self, other: Self) -> Self {
155+
fn update_scc(&mut self, other: &Self) {
188156
trace!("{:?} << {:?}", self.representative, other.representative);
189-
190-
Self {
191-
representative: self.representative.min(other.representative),
192-
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
193-
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
194-
}
157+
self.representative = self.representative.min(other.representative);
158+
self.update_reachable(other);
195159
}
196160

197-
fn merge_reached(self, other: Self) -> Self {
198-
Self {
199-
max_nameable_universe: self.max_nameable_universe.min(other.max_nameable_universe),
200-
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
201-
representative: self.representative,
202-
}
161+
fn update_reachable(&mut self, other: &Self) {
162+
self.max_nameable_universe = self.max_nameable_universe.min(other.max_nameable_universe);
163+
match (self.reachable_placeholders.as_mut(), other.reachable_placeholders.as_ref()) {
164+
(None, None) | (Some(_), None) => (),
165+
(None, Some(theirs)) => self.reachable_placeholders = Some(*theirs),
166+
(Some(ours), Some(theirs)) => ours.merge(theirs),
167+
};
203168
}
204169
}
205170

compiler/rustc_data_structures/src/graph/scc/mod.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,18 @@ mod tests;
2727
/// the max/min element of the SCC, or all of the above.
2828
///
2929
/// Concretely, the both merge operations must commute, e.g. where `merge`
30-
/// is `merge_scc` and `merge_reached`: `a.merge(b) == b.merge(a)`
30+
/// is `update_scc` and `update_reached`: `a.merge(b) == b.merge(a)`
3131
///
3232
/// In general, what you want is probably always min/max according
3333
/// to some ordering, potentially with side constraints (min x such
3434
/// that P holds).
3535
pub trait Annotation: Debug + Copy {
3636
/// Merge two existing annotations into one during
37-
/// path compression.o
38-
fn merge_scc(self, other: Self) -> Self;
37+
/// path compression.
38+
fn update_scc(&mut self, other: &Self);
3939

4040
/// Merge a successor into this annotation.
41-
fn merge_reached(self, other: Self) -> Self;
42-
43-
fn update_scc(&mut self, other: Self) {
44-
*self = self.merge_scc(other)
45-
}
46-
47-
fn update_reachable(&mut self, other: Self) {
48-
*self = self.merge_reached(other)
49-
}
41+
fn update_reachable(&mut self, other: &Self);
5042
}
5143

5244
/// An accumulator for annotations.
@@ -70,12 +62,8 @@ impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
7062

7163
/// The empty annotation, which does nothing.
7264
impl Annotation for () {
73-
fn merge_reached(self, _other: Self) -> Self {
74-
()
75-
}
76-
fn merge_scc(self, _other: Self) -> Self {
77-
()
78-
}
65+
fn update_reachable(&mut self, _other: &Self) {}
66+
fn update_scc(&mut self, _other: &Self) {}
7967
}
8068

8169
/// Strongly connected components (SCC) of a graph. The type `N` is
@@ -289,7 +277,7 @@ enum NodeState<N, S, A: Annotation> {
289277
#[derive(Copy, Clone, Debug)]
290278
enum WalkReturn<S, A: Annotation> {
291279
/// The walk found a cycle, but the entire component is not known to have
292-
/// been fully walked yet. We only know the minimum depth of this
280+
/// been fully walked yet. We only know the minimum depth of this
293281
/// component in a minimum spanning tree of the graph. This component
294282
/// is tentatively represented by the state of the first node of this
295283
/// cycle we met, which is at `min_depth`.
@@ -614,7 +602,7 @@ where
614602
*min_depth = successor_min_depth;
615603
*min_cycle_root = successor_node;
616604
}
617-
current_component_annotation.update_scc(successor_annotation);
605+
current_component_annotation.update_scc(&successor_annotation);
618606
}
619607
// The starting node `node` is succeeded by a fully identified SCC
620608
// which is now added to the set under `scc_index`.
@@ -629,7 +617,7 @@ where
629617
// the `successors_stack` for later.
630618
trace!(?node, ?successor_scc_index);
631619
successors_stack.push(successor_scc_index);
632-
current_component_annotation.update_reachable(successor_annotation);
620+
current_component_annotation.update_reachable(&successor_annotation);
633621
}
634622
// `node` has no more (direct) successors; search recursively.
635623
None => {

compiler/rustc_data_structures/src/graph/scc/tests.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ impl Maxes {
3232
}
3333

3434
impl Annotation for MaxReached {
35-
fn merge_scc(self, other: Self) -> Self {
36-
Self(std::cmp::max(other.0, self.0))
35+
fn update_scc(&mut self, other: &Self) {
36+
self.0 = self.0.max(other.0);
3737
}
3838

39-
fn merge_reached(self, other: Self) -> Self {
40-
Self(std::cmp::max(other.0, self.0))
39+
fn update_reachable(&mut self, other: &Self) {
40+
self.0 = self.0.max(other.0);
4141
}
4242
}
4343

@@ -75,13 +75,12 @@ impl Annotations<usize> for MinMaxes {
7575
}
7676

7777
impl Annotation for MinMaxIn {
78-
fn merge_scc(self, other: Self) -> Self {
79-
Self { min: std::cmp::min(self.min, other.min), max: std::cmp::max(self.max, other.max) }
78+
fn update_scc(&mut self, other: &Self) {
79+
self.min = self.min.min(other.min);
80+
self.max = self.max.max(other.max);
8081
}
8182

82-
fn merge_reached(self, _other: Self) -> Self {
83-
self
84-
}
83+
fn update_reachable(&mut self, _other: &Self) {}
8584
}
8685

8786
#[test]

0 commit comments

Comments
 (0)