Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4680f89

Browse files
committed
Move handling of placeholders out of the borrow checker
This commit moves all handling of placeholders, including those in type-tests, into a pre-processing step of the borrowcheck. Along the way it extends the SCC metadata tracking a lot and uses the extra information to add p: 'static for any placeholder that reaches another placeholder. It also rewrites type-tests that have the same behaviour. Error reporting is handled by introducing a new constraint kind that remembers which original outlives constraint caused an outlives-static. These work a lot like a HTTP redirect response during constraint search. `RegionInferenceContext` is now a lot simpler and only tracks opaque regions without caring about their origin. It also inlines the few measly bits of `init_free_and_bound_regions()` that still remain as relevant. This increases the constructor for `RegionInferenceContext`s somewhat, but I still think it's readable. The documentation for `init_free_and_bound_regions()` was out of date, and the correct, up to date version is available in the various places where the logic was moved. As a drive-by it also refactors the blame search somewhat, renames a few methods, and allows iterating over outgoing constraints without the implied edges from 'static.
1 parent 96cfc75 commit 4680f89

File tree

26 files changed

+1815
-1049
lines changed

26 files changed

+1815
-1049
lines changed

compiler/rustc_borrowck/src/constraints/graph.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,17 @@ impl<D: ConstraintGraphDirection> ConstraintGraph<D> {
106106
}
107107

108108
/// Given a region `R`, iterate over all constraints `R: R1`.
109+
/// if `static_region` is `None`, do not yield implicit
110+
/// `'static -> a` edges.
109111
pub(crate) fn outgoing_edges<'a, 'tcx>(
110112
&'a self,
111113
region_sup: RegionVid,
112114
constraints: &'a OutlivesConstraintSet<'tcx>,
113-
static_region: RegionVid,
115+
static_region: Option<RegionVid>,
114116
) -> Edges<'a, 'tcx, D> {
115117
//if this is the `'static` region and the graph's direction is normal,
116118
//then setup the Edges iterator to return all regions #53178
117-
if region_sup == static_region && D::is_normal() {
119+
if Some(region_sup) == static_region && D::is_normal() {
118120
Edges {
119121
graph: self,
120122
constraints,
@@ -135,7 +137,7 @@ pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> {
135137
constraints: &'a OutlivesConstraintSet<'tcx>,
136138
pointer: Option<OutlivesConstraintIndex>,
137139
next_static_idx: Option<usize>,
138-
static_region: RegionVid,
140+
static_region: Option<RegionVid>,
139141
}
140142

141143
impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> {
@@ -153,8 +155,12 @@ impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> {
153155
Some(next_static_idx + 1)
154156
};
155157

158+
let Some(static_region) = self.static_region else {
159+
return None;
160+
};
161+
156162
Some(OutlivesConstraint {
157-
sup: self.static_region,
163+
sup: static_region,
158164
sub: next_static_idx.into(),
159165
locations: Locations::All(DUMMY_SP),
160166
span: DUMMY_SP,
@@ -194,7 +200,11 @@ impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> {
194200
/// there exists a constraint `R: R1`.
195201
pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> {
196202
Successors {
197-
edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region),
203+
edges: self.constraint_graph.outgoing_edges(
204+
region_sup,
205+
self.set,
206+
Some(self.static_region),
207+
),
198208
}
199209
}
200210
}

compiler/rustc_borrowck/src/constraints/mod.rs

Lines changed: 29 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use std::fmt;
22
use std::ops::Index;
33

4+
use rustc_data_structures::graph::scc;
45
use rustc_index::{IndexSlice, IndexVec};
56
use rustc_middle::mir::ConstraintCategory;
67
use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
78
use rustc_span::Span;
8-
use tracing::{debug, instrument};
9+
use tracing::debug;
910

10-
use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
1111
use crate::type_check::Locations;
12-
use crate::universal_regions::UniversalRegions;
1312

1413
pub(crate) mod graph;
1514

@@ -57,105 +56,39 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
5756
/// Computes cycles (SCCs) in the graph of regions. In particular,
5857
/// find all regions R1, R2 such that R1: R2 and R2: R1 and group
5958
/// them into an SCC, and find the relationships between SCCs.
60-
pub(crate) fn compute_sccs(
59+
pub(crate) fn compute_sccs<
60+
A: scc::Annotation,
61+
AA: scc::Annotations<RegionVid, ConstraintSccIndex, A>,
62+
>(
6163
&self,
6264
static_region: RegionVid,
63-
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
64-
) -> ConstraintSccs {
65-
let constraint_graph = self.graph(definitions.len());
65+
num_region_vars: usize,
66+
annotations: &mut AA,
67+
) -> scc::Sccs<RegionVid, ConstraintSccIndex> {
68+
let constraint_graph = self.graph(num_region_vars);
6669
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-
})
70+
scc::Sccs::new_with_annotation(&region_graph, annotations)
7071
}
7172

72-
/// This method handles Universe errors by rewriting the constraint
73-
/// graph. For each strongly connected component in the constraint
74-
/// graph such that there is a series of constraints
75-
/// A: B: C: ... : X where
76-
/// A's universe is smaller than X's and A is a placeholder,
77-
/// add a constraint that A: 'static. This is a safe upper bound
78-
/// in the face of borrow checker/trait solver limitations that will
79-
/// eventually go away.
80-
///
81-
/// For a more precise definition, see the documentation for
82-
/// [`RegionTracker::has_incompatible_universes()`].
83-
///
84-
/// This edge case used to be handled during constraint propagation
85-
/// by iterating over the strongly connected components in the constraint
86-
/// graph while maintaining a set of bookkeeping mappings similar
87-
/// to what is stored in `RegionTracker` and manually adding 'sttaic as
88-
/// needed.
89-
///
90-
/// It was rewritten as part of the Polonius project with the goal of moving
91-
/// higher-kindedness concerns out of the path of the borrow checker,
92-
/// for two reasons:
93-
///
94-
/// 1. Implementing Polonius is difficult enough without also
95-
/// handling them.
96-
/// 2. The long-term goal is to handle higher-kinded concerns
97-
/// in the trait solver, where they belong. This avoids
98-
/// logic duplication and allows future trait solvers
99-
/// to compute better bounds than for example our
100-
/// "must outlive 'static" here.
101-
///
102-
/// This code is a stop-gap measure in preparation for the future trait solver.
103-
///
104-
/// Every constraint added by this method is an
105-
/// internal `IllegalUniverse` constraint.
106-
#[instrument(skip(self, universal_regions, definitions))]
107-
pub(crate) fn add_outlives_static(
73+
/// There is a placeholder violation; add a requirement
74+
/// that some SCC outlive static and explain which region
75+
/// reaching which other region caused that.
76+
pub(crate) fn add_placeholder_violation_constraint(
10877
&mut self,
109-
universal_regions: &UniversalRegions<'tcx>,
110-
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
111-
) -> ConstraintSccs {
112-
let fr_static = universal_regions.fr_static;
113-
let sccs = self.compute_sccs(fr_static, definitions);
114-
115-
// Changed to `true` if we added any constraints to `self` and need to
116-
// recompute SCCs.
117-
let mut added_constraints = false;
118-
119-
for scc in sccs.all_sccs() {
120-
// No point in adding 'static: 'static!
121-
// This micro-optimisation makes somewhat sense
122-
// because static outlives *everything*.
123-
if scc == sccs.scc(fr_static) {
124-
continue;
125-
}
126-
127-
let annotation = sccs.annotation(scc);
128-
129-
// If this SCC participates in a universe violation,
130-
// e.g. if it reaches a region with a universe smaller than
131-
// the largest region reached, add a requirement that it must
132-
// outlive `'static`.
133-
if annotation.has_incompatible_universes() {
134-
// Optimisation opportunity: this will add more constraints than
135-
// needed for correctness, since an SCC upstream of another with
136-
// a universe violation will "infect" its downstream SCCs to also
137-
// outlive static.
138-
added_constraints = true;
139-
let scc_representative_outlives_static = OutlivesConstraint {
140-
sup: annotation.representative,
141-
sub: fr_static,
142-
category: ConstraintCategory::IllegalUniverse,
143-
locations: Locations::All(rustc_span::DUMMY_SP),
144-
span: rustc_span::DUMMY_SP,
145-
variance_info: VarianceDiagInfo::None,
146-
from_closure: false,
147-
};
148-
self.push(scc_representative_outlives_static);
149-
}
150-
}
151-
152-
if added_constraints {
153-
// We changed the constraint set and so must recompute SCCs.
154-
self.compute_sccs(fr_static, definitions)
155-
} else {
156-
// If we didn't add any back-edges; no more work needs doing
157-
sccs
158-
}
78+
outlives_static: RegionVid,
79+
blame_from: RegionVid,
80+
blame_to: RegionVid,
81+
fr_static: RegionVid,
82+
) {
83+
self.push(OutlivesConstraint {
84+
sup: outlives_static,
85+
sub: fr_static,
86+
category: ConstraintCategory::IllegalPlaceholder(blame_from, blame_to),
87+
locations: Locations::All(rustc_span::DUMMY_SP),
88+
span: rustc_span::DUMMY_SP,
89+
variance_info: VarianceDiagInfo::None,
90+
from_closure: false,
91+
});
15992
}
16093
}
16194

0 commit comments

Comments
 (0)