Skip to content

Commit 6db3b33

Browse files
committed
More explicit version of placeholder constraint handling
1 parent fe03861 commit 6db3b33

File tree

1 file changed

+98
-35
lines changed

1 file changed

+98
-35
lines changed

compiler/rustc_borrowck/src/handle_placeholders.rs

Lines changed: 98 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,72 @@ impl PlaceholderReachability {
115115
}
116116
}
117117

118+
#[derive(Copy, Debug, Clone)]
119+
120+
enum PlaceholderConstraints {
121+
/// The SCC must be able to name this placeholder, in the SCC.
122+
Name(UniverseIndex),
123+
/// Any placeholder we reach must be nameable from this existential.
124+
NameableBy(RegionVid, UniverseIndex),
125+
/// Both constraints at the same time.
126+
NameAndBeNamed { name: UniverseIndex, nameable_by: (RegionVid, UniverseIndex) },
127+
}
128+
129+
impl PlaceholderConstraints {
130+
fn add_name(self, name: UniverseIndex) -> Self {
131+
use PlaceholderConstraints::*;
132+
133+
match self {
134+
Name(universe_index) => Name(universe_index.min(name)),
135+
NameableBy(nb_rvid, nb_u) => NameAndBeNamed { name, nameable_by: (nb_rvid, nb_u) },
136+
NameAndBeNamed { name: my_name, nameable_by } => {
137+
NameAndBeNamed { name: my_name.min(name), nameable_by }
138+
}
139+
}
140+
}
141+
142+
fn add_nameable_by(self, region_vid: RegionVid, universe: UniverseIndex) -> Self {
143+
use PlaceholderConstraints::*;
144+
145+
match self {
146+
Name(universe_index) => {
147+
NameAndBeNamed { name: universe_index, nameable_by: (region_vid, universe) }
148+
}
149+
NameableBy(my_rvid, my_universe_index) => {
150+
let (u, rvid) = ((my_universe_index, my_rvid)).min((universe, region_vid));
151+
NameableBy(rvid, u)
152+
}
153+
NameAndBeNamed { name, nameable_by } => {
154+
let (u, rvid) = ((nameable_by.1, nameable_by.0)).min((universe, region_vid));
155+
NameAndBeNamed { name, nameable_by: (rvid, u) }
156+
}
157+
}
158+
}
159+
160+
fn merge_scc(self, other: Self) -> Self {
161+
use PlaceholderConstraints::*;
162+
match other {
163+
Name(universe_index) | NameAndBeNamed { name: universe_index, .. } => {
164+
self.add_name(universe_index)
165+
}
166+
_ => self,
167+
}
168+
.merge_reached(other)
169+
}
170+
171+
#[inline(always)]
172+
fn merge_reached(self, reached: Self) -> Self {
173+
use PlaceholderConstraints::*;
174+
match reached {
175+
Name(_) => self,
176+
NameableBy(region_vid, universe_index)
177+
| NameAndBeNamed { nameable_by: (region_vid, universe_index), .. } => {
178+
self.add_nameable_by(region_vid, universe_index)
179+
}
180+
}
181+
}
182+
}
183+
118184
/// An annotation for region graph SCCs that tracks
119185
/// the values of its elements. This annotates a single SCC.
120186
#[derive(Copy, Debug, Clone)]
@@ -125,14 +191,8 @@ pub(crate) struct RegionTracker {
125191
/// regions reachable from this SCC.
126192
min_max_nameable_universe: UniverseIndex,
127193

128-
/// The largest universe of a placeholder in this SCC. Iff
129-
/// an existential can name this universe it's allowed to
130-
/// reach us.
131-
scc_placeholder_largest_universe: Option<UniverseIndex>,
132-
133-
/// The reached existential region with the smallest universe, if any. This
134-
/// is an upper bound on the universe.
135-
min_universe_existential: Option<(UniverseIndex, RegionVid)>,
194+
/// State tracking for exceptional circumstances.
195+
exception: Option<PlaceholderConstraints>,
136196

137197
/// The representative Region Variable Id for this SCC.
138198
pub(crate) representative: Representative,
@@ -141,6 +201,7 @@ pub(crate) struct RegionTracker {
141201
impl RegionTracker {
142202
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
143203
use NllRegionVariableOrigin::*;
204+
use PlaceholderConstraints::*;
144205
use PlaceholderReachability::*;
145206

146207
let min_max_nameable_universe = definition.universe;
@@ -151,8 +212,7 @@ impl RegionTracker {
151212
FreeRegion => Self {
152213
reachable_placeholders: NoPlaceholders,
153214
min_max_nameable_universe,
154-
scc_placeholder_largest_universe: None,
155-
min_universe_existential: None,
215+
exception: None,
156216
representative,
157217
},
158218
Placeholder(_) => Self {
@@ -162,15 +222,13 @@ impl RegionTracker {
162222
max_placeholder: rvid,
163223
},
164224
min_max_nameable_universe,
165-
scc_placeholder_largest_universe: Some(definition.universe),
166-
min_universe_existential: None,
225+
exception: Some(Name(definition.universe)),
167226
representative,
168227
},
169228
Existential { .. } => Self {
170229
reachable_placeholders: NoPlaceholders,
171230
min_max_nameable_universe,
172-
scc_placeholder_largest_universe: None,
173-
min_universe_existential: Some(universe_and_rvid),
231+
exception: Some(NameableBy(rvid, definition.universe)),
174232
representative,
175233
},
176234
}
@@ -211,18 +269,16 @@ impl RegionTracker {
211269
///
212270
/// Returns *a* culprit (there may be more than one).
213271
fn reaches_existential_that_cannot_name_us(&self) -> Option<RegionVid> {
214-
let Some(required_universe) = self.scc_placeholder_largest_universe else {
215-
return None;
216-
};
217-
218-
let Some((reachable_lowest_max_u, reachable_lowest_max_u_rvid)) =
219-
self.min_universe_existential
220-
else {
221-
debug!("SCC universe wasn't lowered by an existential; skipping.");
222-
return None;
223-
};
224-
225-
(!reachable_lowest_max_u.can_name(required_universe)).then_some(reachable_lowest_max_u_rvid)
272+
if let Some(PlaceholderConstraints::NameAndBeNamed {
273+
name: p_u,
274+
nameable_by: (ex_rv, ex_u),
275+
}) = self.exception
276+
&& ex_u.cannot_name(p_u)
277+
{
278+
Some(ex_rv)
279+
} else {
280+
None
281+
}
226282
}
227283

228284
/// Determine if this SCC reaches a placeholder that isn't `placeholder_rvid`,
@@ -262,26 +318,33 @@ impl scc::Annotation for RegionTracker {
262318

263319
Self {
264320
representative: self.representative.min(other.representative),
265-
scc_placeholder_largest_universe: self
266-
.scc_placeholder_largest_universe
267-
.max(other.scc_placeholder_largest_universe),
321+
exception: match (self.exception, other.exception) {
322+
(None, other) | (other, None) => other,
323+
(Some(ours), Some(theirs)) => Some(ours.merge_scc(theirs)),
324+
},
268325
..self.merge_reached(other)
269326
}
270327
}
271328

272329
#[inline(always)]
273330
fn merge_reached(self, other: Self) -> Self {
331+
use PlaceholderConstraints::*;
274332
Self {
275-
min_universe_existential: self
276-
.min_universe_existential
277-
.xor(other.min_universe_existential)
278-
.or_else(|| self.min_universe_existential.min(other.min_universe_existential)),
333+
exception: match (self.exception, other.exception) {
334+
// Propagate only reachability (nameable by).
335+
(None, None) => None,
336+
(None, Some(NameableBy(r, u)))
337+
| (None, Some(NameAndBeNamed { nameable_by: (r, u), .. })) => {
338+
Some(NameableBy(r, u))
339+
}
340+
(Some(_), None) | (None, Some(Name(_))) => self.exception,
341+
(Some(this), Some(that)) => Some(this.merge_reached(that)),
342+
},
279343
min_max_nameable_universe: self
280344
.min_max_nameable_universe
281345
.min(other.min_max_nameable_universe),
282346
reachable_placeholders: self.reachable_placeholders.merge(other.reachable_placeholders),
283347
representative: self.representative,
284-
scc_placeholder_largest_universe: self.scc_placeholder_largest_universe,
285348
}
286349
}
287350
}
@@ -363,7 +426,7 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
363426
mut outlives_constraints,
364427
universe_causes,
365428
type_tests,
366-
placeholder_to_region: _
429+
placeholder_to_region: _,
367430
} = constraints;
368431

369432
let fr_static = universal_regions.fr_static;

0 commit comments

Comments
 (0)