Skip to content

Decouple SCC annotations from SCCs #139965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions compiler/rustc_borrowck/src/constraints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
use rustc_span::Span;
use tracing::{debug, instrument};

use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations};
use crate::type_check::Locations;
use crate::universal_regions::UniversalRegions;

Expand Down Expand Up @@ -61,12 +61,14 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
&self,
static_region: RegionVid,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
) -> ConstraintSccs {
) -> AnnotatedSccs {
let constraint_graph = self.graph(definitions.len());
let region_graph = &constraint_graph.region_graph(self, static_region);
ConstraintSccs::new_with_annotation(&region_graph, |r| {
RegionTracker::new(r, &definitions[r])
})
let mut annotation_visitor = SccAnnotations::new(definitions);
(
ConstraintSccs::new_with_annotation(&region_graph, &mut annotation_visitor),
annotation_visitor.scc_to_annotation,
)
}

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

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

let annotation = sccs.annotation(scc);
let annotation = annotations[scc];

// If this SCC participates in a universe violation,
// e.g. if it reaches a region with a universe smaller than
Expand Down Expand Up @@ -154,7 +156,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
self.compute_sccs(fr_static, definitions)
} else {
// If we didn't add any back-edges; no more work needs doing
sccs
(sccs, annotations)
}
}
}
Expand Down
53 changes: 43 additions & 10 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ mod reverse_sccs;

pub(crate) mod values;

pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, RegionTracker>;
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex>;
pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec<ConstraintSccIndex, RegionTracker>);

/// An annotation for region graph SCCs that tracks
/// the values of its elements.
/// the values of its elements. This annotates a single SCC.
#[derive(Copy, Debug, Clone)]
pub struct RegionTracker {
pub(crate) struct RegionTracker {
/// The largest universe of a placeholder reached from this SCC.
/// This includes placeholders within this SCC.
max_placeholder_universe_reached: UniverseIndex,
Expand Down Expand Up @@ -95,6 +96,31 @@ impl scc::Annotation for RegionTracker {
}
}

/// A Visitor for SCC annotation construction.
pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
}

impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
pub(crate) fn new(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
Self { scc_to_annotation: IndexVec::new(), definitions }
}
}

impl scc::Annotations<RegionVid, ConstraintSccIndex, RegionTracker>
for SccAnnotations<'_, '_, RegionTracker>
{
fn new(&self, element: RegionVid) -> RegionTracker {
RegionTracker::new(element, &self.definitions[element])
}

fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
let idx = self.scc_to_annotation.push(annotation);
assert!(idx == scc);
}
}

impl RegionTracker {
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
let (representative_is_placeholder, representative_is_existential) = match definition.origin
Expand Down Expand Up @@ -166,6 +192,8 @@ pub struct RegionInferenceContext<'tcx> {
/// compute the values of each region.
constraint_sccs: ConstraintSccs,

scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,

/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
/// `B: A`. This is used to compute the universal regions that are required
/// to outlive a given SCC. Computed lazily.
Expand Down Expand Up @@ -428,7 +456,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.map(|info| RegionDefinition::new(info.universe, info.origin))
.collect();

let constraint_sccs =
let (constraint_sccs, scc_annotations) =
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
let constraints = Frozen::freeze(outlives_constraints);
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
Expand All @@ -455,6 +483,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
constraints,
constraint_graph,
constraint_sccs,
scc_annotations,
rev_scc_graph: None,
member_constraints,
member_constraints_applied: Vec::new(),
Expand Down Expand Up @@ -752,6 +781,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
debug!(value = ?self.scc_values.region_value_str(scc_a));
}

fn scc_annotations(&self) -> &IndexVec<ConstraintSccIndex, RegionTracker> {
&self.scc_annotations
}

/// Invoked for each `R0 member of [R1..Rn]` constraint.
///
/// `scc` is the SCC containing R0, and `choice_regions` are the
Expand Down Expand Up @@ -793,7 +826,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {

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

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

// If scc_b's declared universe is a subset of
Expand Down Expand Up @@ -986,7 +1019,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
"lower_bound = {:?} r_scc={:?} universe={:?}",
lower_bound,
r_scc,
self.constraint_sccs.annotation(r_scc).min_universe()
self.scc_annotations()[r_scc].min_universe()
);
// If the type test requires that `T: 'a` where `'a` is a
// placeholder from another universe, that effectively requires
Expand Down Expand Up @@ -1467,7 +1500,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// The minimum universe of any variable reachable from this
/// SCC, inside or outside of it.
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
self.constraint_sccs().annotation(scc).min_universe()
self.scc_annotations()[scc].min_universe()
}

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

pub(crate) fn liveness_constraints(&self) -> &LivenessValues {
Expand Down
Loading
Loading