Skip to content

Commit 0d93b4c

Browse files
committed
Keep binder region constraints local while relating
1 parent e902f67 commit 0d93b4c

2 files changed

Lines changed: 227 additions & 52 deletions

File tree

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,12 +1270,19 @@ where
12701270
lhs: T,
12711271
rhs: T,
12721272
) -> Result<(), NoSolution> {
1273-
let result = self.delegate.eq_structurally_relating_aliases(
1274-
param_env,
1275-
lhs,
1276-
rhs,
1277-
self.origin_span,
1278-
)?;
1273+
let result = if self.cx().assumptions_on_binders() {
1274+
let (goals, region_constraints) =
1275+
self.delegate.eq_structurally_relating_aliases_with_region_constraints(
1276+
param_env,
1277+
lhs,
1278+
rhs,
1279+
self.origin_span,
1280+
)?;
1281+
self.register_solver_region_constraint(region_constraints);
1282+
goals
1283+
} else {
1284+
self.delegate.eq_structurally_relating_aliases(param_env, lhs, rhs, self.origin_span)?
1285+
};
12791286
assert_eq!(result, vec![]);
12801287
Ok(())
12811288
}
@@ -1298,7 +1305,19 @@ where
12981305
variance: ty::Variance,
12991306
rhs: T,
13001307
) -> Result<(), NoSolution> {
1301-
let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?;
1308+
let goals = if self.cx().assumptions_on_binders() {
1309+
let (goals, region_constraints) = self.delegate.relate_with_region_constraints(
1310+
param_env,
1311+
lhs,
1312+
variance,
1313+
rhs,
1314+
self.origin_span,
1315+
)?;
1316+
self.register_solver_region_constraint(region_constraints);
1317+
goals
1318+
} else {
1319+
self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?
1320+
};
13021321
for &goal in goals.iter() {
13031322
let source = match goal.predicate.kind().skip_binder() {
13041323
ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {
@@ -1320,12 +1339,30 @@ where
13201339
/// goals correctly.
13211340
#[instrument(level = "trace", skip(self, param_env), ret)]
13221341
pub(super) fn eq_and_get_goals<T: Relate<I>>(
1323-
&self,
1342+
&mut self,
13241343
param_env: I::ParamEnv,
13251344
lhs: T,
13261345
rhs: T,
13271346
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
1328-
Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?)
1347+
if self.cx().assumptions_on_binders() {
1348+
let (goals, region_constraints) = self.delegate.relate_with_region_constraints(
1349+
param_env,
1350+
lhs,
1351+
ty::Variance::Invariant,
1352+
rhs,
1353+
self.origin_span,
1354+
)?;
1355+
self.register_solver_region_constraint(region_constraints);
1356+
Ok(goals)
1357+
} else {
1358+
Ok(self.delegate.relate(
1359+
param_env,
1360+
lhs,
1361+
ty::Variance::Invariant,
1362+
rhs,
1363+
self.origin_span,
1364+
)?)
1365+
}
13291366
}
13301367

13311368
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(

compiler/rustc_type_ir/src/relate/solver_relating.rs

Lines changed: 181 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,70 @@ pub trait RelateExt: InferCtxtLike {
3131
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
3232
TypeError<Self::Interner>,
3333
>;
34+
35+
fn eq_structurally_relating_aliases_with_region_constraints<T: Relate<Self::Interner>>(
36+
&self,
37+
param_env: <Self::Interner as Interner>::ParamEnv,
38+
lhs: T,
39+
rhs: T,
40+
span: <Self::Interner as Interner>::Span,
41+
) -> Result<
42+
(
43+
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
44+
RegionConstraint<Self::Interner>,
45+
),
46+
TypeError<Self::Interner>,
47+
>;
48+
49+
fn relate_with_region_constraints<T: Relate<Self::Interner>>(
50+
&self,
51+
param_env: <Self::Interner as Interner>::ParamEnv,
52+
lhs: T,
53+
variance: ty::Variance,
54+
rhs: T,
55+
span: <Self::Interner as Interner>::Span,
56+
) -> Result<
57+
(
58+
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
59+
RegionConstraint<Self::Interner>,
60+
),
61+
TypeError<Self::Interner>,
62+
>;
63+
}
64+
65+
fn relate_with_options<Infcx, T>(
66+
infcx: &Infcx,
67+
structurally_relate_aliases: StructurallyRelateAliases,
68+
param_env: <Infcx::Interner as Interner>::ParamEnv,
69+
lhs: T,
70+
variance: ty::Variance,
71+
rhs: T,
72+
span: <Infcx::Interner as Interner>::Span,
73+
collect_region_constraints: bool,
74+
) -> Result<
75+
(
76+
Vec<Goal<Infcx::Interner, <Infcx::Interner as Interner>::Predicate>>,
77+
Option<RegionConstraint<Infcx::Interner>>,
78+
),
79+
TypeError<Infcx::Interner>,
80+
>
81+
where
82+
Infcx: InferCtxtLike,
83+
T: Relate<Infcx::Interner>,
84+
{
85+
let mut relate = SolverRelating::build(
86+
infcx,
87+
structurally_relate_aliases,
88+
variance,
89+
param_env,
90+
span,
91+
collect_region_constraints.then(Vec::new),
92+
);
93+
relate.relate(lhs, rhs)?;
94+
Ok((
95+
relate.goals,
96+
relate.region_constraints.map(|c| RegionConstraint::And(c.into_boxed_slice())),
97+
))
3498
}
3599

36100
impl<Infcx: InferCtxtLike> RelateExt for Infcx {
@@ -45,10 +109,17 @@ impl<Infcx: InferCtxtLike> RelateExt for Infcx {
45109
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
46110
TypeError<Self::Interner>,
47111
> {
48-
let mut relate =
49-
SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span);
50-
relate.relate(lhs, rhs)?;
51-
Ok(relate.goals)
112+
let (goals, _) = relate_with_options(
113+
self,
114+
StructurallyRelateAliases::No,
115+
param_env,
116+
lhs,
117+
variance,
118+
rhs,
119+
span,
120+
false,
121+
)?;
122+
Ok(goals)
52123
}
53124

54125
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
@@ -61,15 +132,70 @@ impl<Infcx: InferCtxtLike> RelateExt for Infcx {
61132
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
62133
TypeError<Self::Interner>,
63134
> {
64-
let mut relate = SolverRelating::new(
135+
let (goals, _) = relate_with_options(
65136
self,
66137
StructurallyRelateAliases::Yes,
138+
param_env,
139+
lhs,
67140
ty::Invariant,
141+
rhs,
142+
span,
143+
false,
144+
)?;
145+
Ok(goals)
146+
}
147+
148+
fn eq_structurally_relating_aliases_with_region_constraints<T: Relate<Self::Interner>>(
149+
&self,
150+
param_env: <Self::Interner as Interner>::ParamEnv,
151+
lhs: T,
152+
rhs: T,
153+
span: <Self::Interner as Interner>::Span,
154+
) -> Result<
155+
(
156+
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
157+
RegionConstraint<Self::Interner>,
158+
),
159+
TypeError<Self::Interner>,
160+
> {
161+
let (goals, region_constraints) = relate_with_options(
162+
self,
163+
StructurallyRelateAliases::Yes,
68164
param_env,
165+
lhs,
166+
ty::Invariant,
167+
rhs,
69168
span,
70-
);
71-
relate.relate(lhs, rhs)?;
72-
Ok(relate.goals)
169+
true,
170+
)?;
171+
Ok((goals, region_constraints.unwrap()))
172+
}
173+
174+
fn relate_with_region_constraints<T: Relate<Self::Interner>>(
175+
&self,
176+
param_env: <Self::Interner as Interner>::ParamEnv,
177+
lhs: T,
178+
variance: ty::Variance,
179+
rhs: T,
180+
span: <Self::Interner as Interner>::Span,
181+
) -> Result<
182+
(
183+
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
184+
RegionConstraint<Self::Interner>,
185+
),
186+
TypeError<Self::Interner>,
187+
> {
188+
let (goals, region_constraints) = relate_with_options(
189+
self,
190+
StructurallyRelateAliases::No,
191+
param_env,
192+
lhs,
193+
variance,
194+
rhs,
195+
span,
196+
true,
197+
)?;
198+
Ok((goals, region_constraints.unwrap()))
73199
}
74200
}
75201

@@ -83,6 +209,7 @@ pub struct SolverRelating<'infcx, Infcx, I: Interner> {
83209
// Mutable fields.
84210
ambient_variance: ty::Variance,
85211
goals: Vec<Goal<I, I::Predicate>>,
212+
region_constraints: Option<Vec<RegionConstraint<I>>>,
86213
/// The cache only tracks the `ambient_variance` as it's the
87214
/// only field which is mutable and which meaningfully changes
88215
/// the result when relating types.
@@ -119,6 +246,17 @@ where
119246
ambient_variance: ty::Variance,
120247
param_env: I::ParamEnv,
121248
span: I::Span,
249+
) -> Self {
250+
Self::build(infcx, structurally_relate_aliases, ambient_variance, param_env, span, None)
251+
}
252+
253+
fn build(
254+
infcx: &'infcx Infcx,
255+
structurally_relate_aliases: StructurallyRelateAliases,
256+
ambient_variance: ty::Variance,
257+
param_env: I::ParamEnv,
258+
span: I::Span,
259+
region_constraints: Option<Vec<RegionConstraint<I>>>,
122260
) -> Self {
123261
SolverRelating {
124262
infcx,
@@ -127,6 +265,7 @@ where
127265
ambient_variance,
128266
param_env,
129267
goals: vec![],
268+
region_constraints,
130269
cache: Default::default(),
131270
}
132271
}
@@ -255,43 +394,42 @@ where
255394

256395
#[instrument(skip(self), level = "trace")]
257396
fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region> {
258-
if self.cx().assumptions_on_binders() {
259-
if a == b {
260-
return Ok(a);
397+
match self.ambient_variance {
398+
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
399+
ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span),
400+
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
401+
ty::Contravariant => self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span),
402+
ty::Invariant => self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span),
403+
ty::Bivariant => {
404+
unreachable!("Expected bivariance to be handled in relate_with_variance")
261405
}
406+
}
262407

263-
match self.ambient_variance {
264-
ty::Covariant => {
265-
self.infcx
266-
.register_solver_region_constraint(RegionConstraint::RegionOutlives(a, b));
267-
}
268-
ty::Contravariant => {
269-
self.infcx
270-
.register_solver_region_constraint(RegionConstraint::RegionOutlives(b, a));
271-
}
272-
ty::Invariant => {
273-
self.infcx
274-
.register_solver_region_constraint(RegionConstraint::RegionOutlives(a, b));
275-
self.infcx
276-
.register_solver_region_constraint(RegionConstraint::RegionOutlives(b, a));
277-
}
278-
ty::Bivariant => {
279-
unreachable!("Expected bivariance to be handled in relate_with_variance")
280-
}
281-
}
282-
} else {
283-
match self.ambient_variance {
284-
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
285-
ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span),
286-
// Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b)
287-
ty::Contravariant => {
288-
self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span)
289-
}
290-
ty::Invariant => {
291-
self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span)
292-
}
293-
ty::Bivariant => {
294-
unreachable!("Expected bivariance to be handled in relate_with_variance")
408+
let resolve_region = |r: I::Region| match r.kind() {
409+
ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
410+
_ => r,
411+
};
412+
let a = resolve_region(a);
413+
let b = resolve_region(b);
414+
415+
if let Some(region_constraints) = &mut self.region_constraints {
416+
if a == b {
417+
return Ok(a);
418+
} else {
419+
match self.ambient_variance {
420+
ty::Covariant => {
421+
region_constraints.push(RegionConstraint::RegionOutlives(a, b));
422+
}
423+
ty::Contravariant => {
424+
region_constraints.push(RegionConstraint::RegionOutlives(b, a));
425+
}
426+
ty::Invariant => {
427+
region_constraints.push(RegionConstraint::RegionOutlives(a, b));
428+
region_constraints.push(RegionConstraint::RegionOutlives(b, a));
429+
}
430+
ty::Bivariant => {
431+
unreachable!("Expected bivariance to be handled in relate_with_variance")
432+
}
295433
}
296434
}
297435
}

0 commit comments

Comments
 (0)