Skip to content

Commit f294181

Browse files
committed
Decouple SCC annotations from SCCs
This rewires SCC annotations to have them be a separate, visitor-type data structure. It was broken out of #130227, which needed them to be able to remove unused annotations after computation without recomputing the SCCs themselves. As a drive-by it also removes some redundant code from the hot loop in SCC construction for a performance improvement.
1 parent c4b38a5 commit f294181

File tree

4 files changed

+228
-159
lines changed

4 files changed

+228
-159
lines changed

compiler/rustc_borrowck/src/constraints/mod.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
77
use rustc_span::Span;
88
use tracing::{debug, instrument};
99

10-
use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
10+
use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations};
1111
use crate::type_check::Locations;
1212
use crate::universal_regions::UniversalRegions;
1313

@@ -61,12 +61,14 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
6161
&self,
6262
static_region: RegionVid,
6363
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
64-
) -> ConstraintSccs {
64+
) -> AnnotatedSccs {
6565
let constraint_graph = self.graph(definitions.len());
6666
let region_graph = &constraint_graph.region_graph(self, static_region);
67-
ConstraintSccs::new_with_annotation(&region_graph, |r| {
68-
RegionTracker::new(r, &definitions[r])
69-
})
67+
let mut annotation_visitor = SccAnnotations::new(definitions);
68+
(
69+
ConstraintSccs::new_with_annotation(&region_graph, &mut annotation_visitor),
70+
annotation_visitor.scc_to_annotation,
71+
)
7072
}
7173

7274
/// This method handles Universe errors by rewriting the constraint
@@ -79,12 +81,12 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
7981
/// eventually go away.
8082
///
8183
/// For a more precise definition, see the documentation for
82-
/// [`RegionTracker::has_incompatible_universes()`].
84+
/// [`crate::region_infer::RegionTracker`].
8385
///
8486
/// This edge case used to be handled during constraint propagation
8587
/// by iterating over the strongly connected components in the constraint
8688
/// graph while maintaining a set of bookkeeping mappings similar
87-
/// to what is stored in `RegionTracker` and manually adding 'sttaic as
89+
/// to what is stored in `RegionTracker` and manually adding 'static as
8890
/// needed.
8991
///
9092
/// It was rewritten as part of the Polonius project with the goal of moving
@@ -108,9 +110,9 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
108110
&mut self,
109111
universal_regions: &UniversalRegions<'tcx>,
110112
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
111-
) -> ConstraintSccs {
113+
) -> AnnotatedSccs {
112114
let fr_static = universal_regions.fr_static;
113-
let sccs = self.compute_sccs(fr_static, definitions);
115+
let (sccs, annotations) = self.compute_sccs(fr_static, definitions);
114116

115117
// Changed to `true` if we added any constraints to `self` and need to
116118
// recompute SCCs.
@@ -124,7 +126,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
124126
continue;
125127
}
126128

127-
let annotation = sccs.annotation(scc);
129+
let annotation = annotations[scc];
128130

129131
// If this SCC participates in a universe violation,
130132
// e.g. if it reaches a region with a universe smaller than
@@ -154,7 +156,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
154156
self.compute_sccs(fr_static, definitions)
155157
} else {
156158
// If we didn't add any back-edges; no more work needs doing
157-
sccs
159+
(sccs, annotations)
158160
}
159161
}
160162
}

compiler/rustc_borrowck/src/region_infer/mod.rs

+43-10
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ mod reverse_sccs;
4545

4646
pub(crate) mod values;
4747

48-
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, RegionTracker>;
48+
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex>;
49+
pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec<ConstraintSccIndex, RegionTracker>);
4950

5051
/// An annotation for region graph SCCs that tracks
51-
/// the values of its elements.
52+
/// the values of its elements. This annotates a single SCC.
5253
#[derive(Copy, Debug, Clone)]
53-
pub struct RegionTracker {
54+
pub(crate) struct RegionTracker {
5455
/// The largest universe of a placeholder reached from this SCC.
5556
/// This includes placeholders within this SCC.
5657
max_placeholder_universe_reached: UniverseIndex,
@@ -95,6 +96,31 @@ impl scc::Annotation for RegionTracker {
9596
}
9697
}
9798

99+
/// A Visitor for SCC annotation construction.
100+
pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
101+
pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
102+
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
103+
}
104+
105+
impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
106+
pub(crate) fn new(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
107+
Self { scc_to_annotation: IndexVec::new(), definitions }
108+
}
109+
}
110+
111+
impl scc::Annotations<RegionVid, ConstraintSccIndex, RegionTracker>
112+
for SccAnnotations<'_, '_, RegionTracker>
113+
{
114+
fn new(&self, element: RegionVid) -> RegionTracker {
115+
RegionTracker::new(element, &self.definitions[element])
116+
}
117+
118+
fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
119+
let idx = self.scc_to_annotation.push(annotation);
120+
assert!(idx == scc);
121+
}
122+
}
123+
98124
impl RegionTracker {
99125
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
100126
let (representative_is_placeholder, representative_is_existential) = match definition.origin
@@ -166,6 +192,8 @@ pub struct RegionInferenceContext<'tcx> {
166192
/// compute the values of each region.
167193
constraint_sccs: ConstraintSccs,
168194

195+
scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
196+
169197
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
170198
/// `B: A`. This is used to compute the universal regions that are required
171199
/// to outlive a given SCC. Computed lazily.
@@ -428,7 +456,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
428456
.map(|info| RegionDefinition::new(info.universe, info.origin))
429457
.collect();
430458

431-
let constraint_sccs =
459+
let (constraint_sccs, scc_annotations) =
432460
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
433461
let constraints = Frozen::freeze(outlives_constraints);
434462
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
@@ -455,6 +483,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
455483
constraints,
456484
constraint_graph,
457485
constraint_sccs,
486+
scc_annotations,
458487
rev_scc_graph: None,
459488
member_constraints,
460489
member_constraints_applied: Vec::new(),
@@ -752,6 +781,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
752781
debug!(value = ?self.scc_values.region_value_str(scc_a));
753782
}
754783

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

794827
// If the member region lives in a higher universe, we currently choose
795828
// the most conservative option by leaving it unchanged.
796-
if !self.constraint_sccs().annotation(scc).min_universe().is_root() {
829+
if !self.scc_annotations()[scc].min_universe().is_root() {
797830
return;
798831
}
799832

@@ -869,8 +902,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
869902
/// in `scc_a`. Used during constraint propagation, and only once
870903
/// the value of `scc_b` has been computed.
871904
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
872-
let a_annotation = self.constraint_sccs().annotation(scc_a);
873-
let b_annotation = self.constraint_sccs().annotation(scc_b);
905+
let a_annotation = self.scc_annotations()[scc_a];
906+
let b_annotation = self.scc_annotations()[scc_b];
874907
let a_universe = a_annotation.min_universe();
875908

876909
// If scc_b's declared universe is a subset of
@@ -986,7 +1019,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
9861019
"lower_bound = {:?} r_scc={:?} universe={:?}",
9871020
lower_bound,
9881021
r_scc,
989-
self.constraint_sccs.annotation(r_scc).min_universe()
1022+
self.scc_annotations()[r_scc].min_universe()
9901023
);
9911024
// If the type test requires that `T: 'a` where `'a` is a
9921025
// placeholder from another universe, that effectively requires
@@ -1467,7 +1500,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
14671500
/// The minimum universe of any variable reachable from this
14681501
/// SCC, inside or outside of it.
14691502
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
1470-
self.constraint_sccs().annotation(scc).min_universe()
1503+
self.scc_annotations()[scc].min_universe()
14711504
}
14721505

14731506
/// Checks the final value for the free region `fr` to see if it
@@ -2214,7 +2247,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
22142247
/// they *must* be equal (though not having the same repr does not
22152248
/// mean they are unequal).
22162249
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
2217-
self.constraint_sccs.annotation(scc).representative
2250+
self.scc_annotations()[scc].representative
22182251
}
22192252

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

0 commit comments

Comments
 (0)