Skip to content

Commit 5a84e26

Browse files
committed
Use associated types for SCC annotations, per code review suggestion
1 parent f294181 commit 5a84e26

File tree

3 files changed

+50
-49
lines changed

3 files changed

+50
-49
lines changed

compiler/rustc_borrowck/src/region_infer/mod.rs

+10-13
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,7 @@ impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
108108
}
109109
}
110110

111-
impl scc::Annotations<RegionVid, ConstraintSccIndex, RegionTracker>
112-
for SccAnnotations<'_, '_, RegionTracker>
113-
{
111+
impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
114112
fn new(&self, element: RegionVid) -> RegionTracker {
115113
RegionTracker::new(element, &self.definitions[element])
116114
}
@@ -119,6 +117,9 @@ impl scc::Annotations<RegionVid, ConstraintSccIndex, RegionTracker>
119117
let idx = self.scc_to_annotation.push(annotation);
120118
assert!(idx == scc);
121119
}
120+
121+
type Ann = RegionTracker;
122+
type SccIdx = ConstraintSccIndex;
122123
}
123124

124125
impl RegionTracker {
@@ -781,10 +782,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
781782
debug!(value = ?self.scc_values.region_value_str(scc_a));
782783
}
783784

784-
fn scc_annotations(&self) -> &IndexVec<ConstraintSccIndex, RegionTracker> {
785-
&self.scc_annotations
786-
}
787-
788785
/// Invoked for each `R0 member of [R1..Rn]` constraint.
789786
///
790787
/// `scc` is the SCC containing R0, and `choice_regions` are the
@@ -826,7 +823,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
826823

827824
// If the member region lives in a higher universe, we currently choose
828825
// the most conservative option by leaving it unchanged.
829-
if !self.scc_annotations()[scc].min_universe().is_root() {
826+
if !self.scc_universe(scc).is_root() {
830827
return;
831828
}
832829

@@ -902,8 +899,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
902899
/// in `scc_a`. Used during constraint propagation, and only once
903900
/// the value of `scc_b` has been computed.
904901
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
905-
let a_annotation = self.scc_annotations()[scc_a];
906-
let b_annotation = self.scc_annotations()[scc_b];
902+
let a_annotation = self.scc_annotations[scc_a];
903+
let b_annotation = self.scc_annotations[scc_b];
907904
let a_universe = a_annotation.min_universe();
908905

909906
// If scc_b's declared universe is a subset of
@@ -1019,7 +1016,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10191016
"lower_bound = {:?} r_scc={:?} universe={:?}",
10201017
lower_bound,
10211018
r_scc,
1022-
self.scc_annotations()[r_scc].min_universe()
1019+
self.scc_universe(r_scc)
10231020
);
10241021
// If the type test requires that `T: 'a` where `'a` is a
10251022
// placeholder from another universe, that effectively requires
@@ -1500,7 +1497,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
15001497
/// The minimum universe of any variable reachable from this
15011498
/// SCC, inside or outside of it.
15021499
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
1503-
self.scc_annotations()[scc].min_universe()
1500+
self.scc_annotations[scc].min_universe()
15041501
}
15051502

15061503
/// Checks the final value for the free region `fr` to see if it
@@ -2247,7 +2244,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22472244
/// they *must* be equal (though not having the same repr does not
22482245
/// mean they are unequal).
22492246
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
2250-
self.scc_annotations()[scc].representative
2247+
self.scc_annotations[scc].representative
22512248
}
22522249

22532250
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {

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

+32-34
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
use std::assert_matches::debug_assert_matches;
1212
use std::fmt::Debug;
13+
use std::marker::PhantomData;
1314
use std::ops::Range;
1415

1516
use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -49,13 +50,20 @@ pub trait Annotation: Debug + Copy {
4950
}
5051

5152
/// An accumulator for annotations.
52-
pub trait Annotations<N: Idx, S: Idx, A: Annotation> {
53-
fn new(&self, element: N) -> A;
54-
fn annotate_scc(&mut self, scc: S, annotation: A);
53+
pub trait Annotations<N: Idx> {
54+
type Ann: Annotation;
55+
type SccIdx: Idx + Ord;
56+
57+
fn new(&self, element: N) -> Self::Ann;
58+
fn annotate_scc(&mut self, scc: Self::SccIdx, annotation: Self::Ann);
5559
}
5660

5761
/// The nil annotation accumulator, which does nothing.
58-
impl<N: Idx, S: Idx> Annotations<N, S, ()> for () {
62+
struct NoAnnotations<S: Idx + Ord>(PhantomData<S>);
63+
64+
impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
65+
type SccIdx = S;
66+
type Ann = ();
5967
fn new(&self, _element: N) -> () {
6068
()
6169
}
@@ -112,13 +120,13 @@ struct SccData<S: Idx> {
112120
impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
113121
/// Compute SCCs without annotations.
114122
pub fn new(graph: &impl Successors<Node = N>) -> Self {
115-
Self::new_with_annotation(graph, &mut ())
123+
Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::<S>))
116124
}
117125

118126
/// Compute SCCs and annotate them with a user-supplied annotation
119-
pub fn new_with_annotation<A: Annotation, AA: Annotations<N, S, A>>(
127+
pub fn new_with_annotation<A: Annotations<N, SccIdx = S>>(
120128
graph: &impl Successors<Node = N>,
121-
annotations: &mut AA,
129+
annotations: &mut A,
122130
) -> Self {
123131
SccsConstruction::construct(graph, annotations)
124132
}
@@ -141,13 +149,7 @@ impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
141149
pub fn all_sccs(&self) -> impl Iterator<Item = S> + 'static {
142150
(0..self.scc_data.len()).map(S::new)
143151
}
144-
/*
145-
/// Returns an iterator over the SCC annotations in the graph
146-
/// The order is the same as `all_sccs()`, dependency order.
147-
pub fn all_annotations(&self, annotations: &A) -> impl Iterator<Item = (S, A)> + use<'_, N, S, A> {
148-
self.all_sccs().map(|scc| (scc, self.annotation(scc)))
149-
}
150-
*/
152+
151153
/// Returns the SCC to which a node `r` belongs.
152154
pub fn scc(&self, r: N) -> S {
153155
self.scc_indices[r]
@@ -223,19 +225,17 @@ impl<S: Idx> SccData<S> {
223225
}
224226
}
225227

226-
struct SccsConstruction<'c, 'a, G, S, A, AA>
228+
struct SccsConstruction<'c, 'a, G, A>
227229
where
228230
G: DirectedGraph + Successors,
229-
S: Idx,
230-
A: Annotation,
231-
AA: Annotations<G::Node, S, A>,
231+
A: Annotations<G::Node>,
232232
{
233233
graph: &'c G,
234234

235235
/// The state of each node; used during walk to record the stack
236236
/// and after walk to record what cycle each node ended up being
237237
/// in.
238-
node_states: IndexVec<G::Node, NodeState<G::Node, S, A>>,
238+
node_states: IndexVec<G::Node, NodeState<G::Node, A::SccIdx, A::Ann>>,
239239

240240
/// The stack of nodes that we are visiting as part of the DFS.
241241
node_stack: Vec<G::Node>,
@@ -244,21 +244,21 @@ where
244244
/// position in this stack, and when we encounter a successor SCC,
245245
/// we push it on the stack. When we complete an SCC, we can pop
246246
/// everything off the stack that was found along the way.
247-
successors_stack: Vec<S>,
247+
successors_stack: Vec<A::SccIdx>,
248248

249249
/// A set used to strip duplicates. As we accumulate successors
250250
/// into the successors_stack, we sometimes get duplicate entries.
251251
/// We use this set to remove those -- we also keep its storage
252252
/// around between successors to amortize memory allocation costs.
253-
duplicate_set: FxHashSet<S>,
253+
duplicate_set: FxHashSet<A::SccIdx>,
254254

255-
scc_data: SccData<S>,
255+
scc_data: SccData<A::SccIdx>,
256256

257-
annotations: &'a mut AA,
257+
annotations: &'a mut A,
258258
}
259259

260260
#[derive(Copy, Clone, Debug)]
261-
enum NodeState<N, S, A> {
261+
enum NodeState<N, S, A: Annotation> {
262262
/// This node has not yet been visited as part of the DFS.
263263
///
264264
/// After SCC construction is complete, this state ought to be
@@ -289,7 +289,7 @@ enum NodeState<N, S, A> {
289289

290290
/// The state of walking a given node.
291291
#[derive(Copy, Clone, Debug)]
292-
enum WalkReturn<S, A> {
292+
enum WalkReturn<S, A: Annotation> {
293293
/// The walk found a cycle, but the entire component is not known to have
294294
/// been fully walked yet. We only know the minimum depth of this
295295
/// component in a minimum spanning tree of the graph. This component
@@ -302,12 +302,10 @@ enum WalkReturn<S, A> {
302302
Complete { scc_index: S, annotation: A },
303303
}
304304

305-
impl<'c, 'a, G, S, A, AA> SccsConstruction<'c, 'a, G, S, A, AA>
305+
impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A>
306306
where
307307
G: DirectedGraph + Successors,
308-
S: Idx,
309-
A: Annotation,
310-
AA: Annotations<G::Node, S, A>,
308+
A: Annotations<G::Node>,
311309
{
312310
/// Identifies SCCs in the graph `G` and computes the resulting
313311
/// DAG. This uses a variant of [Tarjan's
@@ -323,7 +321,7 @@ where
323321
/// Additionally, we keep track of a current annotation of the SCC.
324322
///
325323
/// [wikipedia]: https://bit.ly/2EZIx84
326-
fn construct(graph: &'c G, annotations: &'a mut AA) -> Sccs<G::Node, S> {
324+
fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs<G::Node, A::SccIdx> {
327325
let num_nodes = graph.num_nodes();
328326

329327
let mut this = Self {
@@ -349,7 +347,7 @@ where
349347
Sccs { scc_indices, scc_data: this.scc_data }
350348
}
351349

352-
fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<S, A> {
350+
fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
353351
self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node))
354352
}
355353

@@ -365,7 +363,7 @@ where
365363
/// Otherwise, we are looking at a node that has already been
366364
/// completely visited. We therefore return `WalkReturn::Complete`
367365
/// with its associated SCC index.
368-
fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<S, A>> {
366+
fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<A::SccIdx, A::Ann>> {
369367
Some(match self.find_state(node) {
370368
NodeState::InCycle { scc_index, annotation } => {
371369
WalkReturn::Complete { scc_index, annotation }
@@ -388,7 +386,7 @@ where
388386
/// of `r2` (and updates `r` to reflect current result). This is
389387
/// basically the "find" part of a standard union-find algorithm
390388
/// (with path compression).
391-
fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, S, A> {
389+
fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, A::SccIdx, A::Ann> {
392390
// To avoid recursion we temporarily reuse the `parent` of each
393391
// InCycleWith link to encode a downwards link while compressing
394392
// the path. After we have found the root or deepest node being
@@ -511,7 +509,7 @@ where
511509
/// caller decide avoids mutual recursion between the two methods and allows
512510
/// us to maintain an allocated stack for nodes on the path between calls.
513511
#[instrument(skip(self, initial), level = "trace")]
514-
fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<S, A> {
512+
fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
515513
trace!("Walk unvisited node: {initial:?}");
516514
struct VisitingNodeFrame<G: DirectedGraph, Successors, A> {
517515
node: G::Node,

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ struct MaxReached(usize);
88
struct Maxes(IndexVec<usize, MaxReached>, fn(usize) -> usize);
99
type UsizeSccs = Sccs<usize, usize>;
1010

11-
impl Annotations<usize, usize, MaxReached> for Maxes {
11+
impl Annotations<usize> for Maxes {
1212
fn new(&self, element: usize) -> MaxReached {
1313
MaxReached(self.1(element))
1414
}
@@ -17,6 +17,9 @@ impl Annotations<usize, usize, MaxReached> for Maxes {
1717
let i = self.0.push(annotation);
1818
assert!(i == scc);
1919
}
20+
21+
type Ann = MaxReached;
22+
type SccIdx = usize;
2023
}
2124

2225
impl Maxes {
@@ -57,7 +60,7 @@ impl MinMaxes {
5760
}
5861
}
5962

60-
impl Annotations<usize, usize, MinMaxIn> for MinMaxes {
63+
impl Annotations<usize> for MinMaxes {
6164
fn new(&self, element: usize) -> MinMaxIn {
6265
self.1(element)
6366
}
@@ -66,6 +69,9 @@ impl Annotations<usize, usize, MinMaxIn> for MinMaxes {
6669
let i = self.0.push(annotation);
6770
assert!(i == scc);
6871
}
72+
73+
type Ann = MinMaxIn;
74+
type SccIdx = usize;
6975
}
7076

7177
impl Annotation for MinMaxIn {

0 commit comments

Comments
 (0)