Skip to content

Commit f392a87

Browse files
committed
freshen: resolve root vars
Without doing so we use the same candidate cache entry for `?0: Trait<?1>` and `?0: Trait<?0>`. These goals are different and we must not use the same entry for them.
1 parent 91535ad commit f392a87

File tree

4 files changed

+103
-97
lines changed

4 files changed

+103
-97
lines changed

Diff for: compiler/rustc_infer/src/infer/freshen.rs

+69-67
Original file line numberDiff line numberDiff line change
@@ -56,49 +56,46 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
5656
}
5757
}
5858

59-
fn freshen_ty<F>(&mut self, opt_ty: Option<Ty<'tcx>>, key: ty::InferTy, mk_fresh: F) -> Ty<'tcx>
59+
fn freshen_ty<F>(&mut self, input: Result<Ty<'tcx>, ty::InferTy>, mk_fresh: F) -> Ty<'tcx>
6060
where
6161
F: FnOnce(u32) -> Ty<'tcx>,
6262
{
63-
if let Some(ty) = opt_ty {
64-
return ty.fold_with(self);
65-
}
66-
67-
match self.ty_freshen_map.entry(key) {
68-
Entry::Occupied(entry) => *entry.get(),
69-
Entry::Vacant(entry) => {
70-
let index = self.ty_freshen_count;
71-
self.ty_freshen_count += 1;
72-
let t = mk_fresh(index);
73-
entry.insert(t);
74-
t
75-
}
63+
match input {
64+
Ok(ty) => ty.fold_with(self),
65+
Err(key) => match self.ty_freshen_map.entry(key) {
66+
Entry::Occupied(entry) => *entry.get(),
67+
Entry::Vacant(entry) => {
68+
let index = self.ty_freshen_count;
69+
self.ty_freshen_count += 1;
70+
let t = mk_fresh(index);
71+
entry.insert(t);
72+
t
73+
}
74+
},
7675
}
7776
}
7877

7978
fn freshen_const<F>(
8079
&mut self,
81-
opt_ct: Option<ty::Const<'tcx>>,
82-
key: ty::InferConst,
80+
input: Result<ty::Const<'tcx>, ty::InferConst>,
8381
freshener: F,
8482
ty: Ty<'tcx>,
8583
) -> ty::Const<'tcx>
8684
where
8785
F: FnOnce(u32) -> ty::InferConst,
8886
{
89-
if let Some(ct) = opt_ct {
90-
return ct.fold_with(self);
91-
}
92-
93-
match self.const_freshen_map.entry(key) {
94-
Entry::Occupied(entry) => *entry.get(),
95-
Entry::Vacant(entry) => {
96-
let index = self.const_freshen_count;
97-
self.const_freshen_count += 1;
98-
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
99-
entry.insert(ct);
100-
ct
101-
}
87+
match input {
88+
Ok(ct) => ct.fold_with(self),
89+
Err(key) => match self.const_freshen_map.entry(key) {
90+
Entry::Occupied(entry) => *entry.get(),
91+
Entry::Vacant(entry) => {
92+
let index = self.const_freshen_count;
93+
self.const_freshen_count += 1;
94+
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
95+
entry.insert(ct);
96+
ct
97+
}
98+
},
10299
}
103100
}
104101
}
@@ -146,19 +143,22 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
146143
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
147144
match ct.kind() {
148145
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
149-
let opt_ct =
150-
self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
151-
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
146+
let mut inner = self.infcx.inner.borrow_mut();
147+
let input =
148+
inner.const_unification_table().probe_value(v).known().ok_or_else(|| {
149+
ty::InferConst::Var(inner.const_unification_table().find(v).vid)
150+
});
151+
drop(inner);
152+
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
152153
}
153154
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
154-
let opt_ct =
155-
self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known();
156-
self.freshen_const(
157-
opt_ct,
158-
ty::InferConst::EffectVar(v),
159-
ty::InferConst::Fresh,
160-
ct.ty(),
161-
)
155+
let mut inner = self.infcx.inner.borrow_mut();
156+
let input =
157+
inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
158+
ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
159+
});
160+
drop(inner);
161+
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
162162
}
163163
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
164164
if i >= self.const_freshen_count {
@@ -191,35 +191,37 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
191191
fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
192192
match v {
193193
ty::TyVar(v) => {
194-
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
195-
Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n)))
194+
let mut inner = self.infcx.inner.borrow_mut();
195+
let input = inner
196+
.type_variables()
197+
.probe(v)
198+
.known()
199+
.ok_or_else(|| ty::TyVar(inner.type_variables().root_var(v)));
200+
drop(inner);
201+
Some(self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n)))
196202
}
197203

198-
ty::IntVar(v) => Some(
199-
self.freshen_ty(
200-
self.infcx
201-
.inner
202-
.borrow_mut()
203-
.int_unification_table()
204-
.probe_value(v)
205-
.map(|v| v.to_type(self.infcx.tcx)),
206-
ty::IntVar(v),
207-
|n| Ty::new_fresh_int(self.infcx.tcx, n),
208-
),
209-
),
210-
211-
ty::FloatVar(v) => Some(
212-
self.freshen_ty(
213-
self.infcx
214-
.inner
215-
.borrow_mut()
216-
.float_unification_table()
217-
.probe_value(v)
218-
.map(|v| v.to_type(self.infcx.tcx)),
219-
ty::FloatVar(v),
220-
|n| Ty::new_fresh_float(self.infcx.tcx, n),
221-
),
222-
),
204+
ty::IntVar(v) => {
205+
let mut inner = self.infcx.inner.borrow_mut();
206+
let input = inner
207+
.int_unification_table()
208+
.probe_value(v)
209+
.map(|v| v.to_type(self.infcx.tcx))
210+
.ok_or_else(|| ty::IntVar(inner.int_unification_table().find(v)));
211+
drop(inner);
212+
Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
213+
}
214+
215+
ty::FloatVar(v) => {
216+
let mut inner = self.infcx.inner.borrow_mut();
217+
let input = inner
218+
.float_unification_table()
219+
.probe_value(v)
220+
.map(|v| v.to_type(self.infcx.tcx))
221+
.ok_or_else(|| ty::FloatVar(inner.float_unification_table().find(v)));
222+
drop(inner);
223+
Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
224+
}
223225

224226
ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
225227
if ct >= self.ty_freshen_count {

Diff for: compiler/rustc_trait_selection/src/traits/select/mod.rs

+2-23
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use rustc_middle::dep_graph::DepNodeIndex;
4040
use rustc_middle::mir::interpret::ErrorHandled;
4141
use rustc_middle::ty::_match::MatchAgainstFreshVars;
4242
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
43-
use rustc_middle::ty::fold::BottomUpFolder;
4443
use rustc_middle::ty::relate::TypeRelation;
4544
use rustc_middle::ty::GenericArgsRef;
4645
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
@@ -2435,28 +2434,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
24352434
match self.match_impl(impl_def_id, impl_trait_header, obligation) {
24362435
Ok(args) => args,
24372436
Err(()) => {
2438-
// FIXME: A rematch may fail when a candidate cache hit occurs
2439-
// on the freshened form of the trait predicate, but the match
2440-
// fails for some reason that is not captured in the freshened
2441-
// cache key. For example, equating an impl trait ref against
2442-
// the placeholder trait ref may fail due the Generalizer relation
2443-
// raising a CyclicalTy error due to a sub_root_var relation
2444-
// for a variable being generalized...
2445-
let guar = self.infcx.dcx().span_delayed_bug(
2446-
obligation.cause.span,
2447-
format!(
2448-
"Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
2449-
),
2450-
);
2451-
let value = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
2452-
let err = Ty::new_error(self.tcx(), guar);
2453-
let value = value.fold_with(&mut BottomUpFolder {
2454-
tcx: self.tcx(),
2455-
ty_op: |_| err,
2456-
lt_op: |l| l,
2457-
ct_op: |c| c,
2458-
});
2459-
Normalized { value, obligations: vec![] }
2437+
let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
2438+
bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not")
24602439
}
24612440
}
24622441
}

Diff for: tests/ui/impl-trait/issues/issue-62742.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::marker::PhantomData;
33
fn _alias_check() {
44
WrongImpl::foo(0i32);
55
//~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
6+
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
7+
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
68
WrongImpl::<()>::foo(0i32);
79
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
810
//~| ERROR trait bounds were not satisfied

Diff for: tests/ui/impl-trait/issues/issue-62742.stderr

+30-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
2+
--> $DIR/issue-62742.rs:4:5
3+
|
4+
LL | WrongImpl::foo(0i32);
5+
| ^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
6+
|
7+
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
8+
note: required by a bound in `SafeImpl::<T, A>::foo`
9+
--> $DIR/issue-62742.rs:30:20
10+
|
11+
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
12+
| ^^^^^^ required by this bound in `SafeImpl::<T, A>::foo`
13+
LL | pub fn foo(value: A::Value) {}
14+
| --- required by a bound in this associated function
15+
116
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
217
--> $DIR/issue-62742.rs:4:5
318
|
@@ -6,13 +21,21 @@ LL | WrongImpl::foo(0i32);
621
|
722
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
823
note: required by a bound in `SafeImpl`
9-
--> $DIR/issue-62742.rs:26:35
24+
--> $DIR/issue-62742.rs:28:35
1025
|
1126
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
1227
| ^^^^^^ required by this bound in `SafeImpl`
1328

29+
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
30+
--> $DIR/issue-62742.rs:4:5
31+
|
32+
LL | WrongImpl::foo(0i32);
33+
| ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
34+
|
35+
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
36+
1437
error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
15-
--> $DIR/issue-62742.rs:6:22
38+
--> $DIR/issue-62742.rs:8:22
1639
|
1740
LL | WrongImpl::<()>::foo(0i32);
1841
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
@@ -24,33 +47,33 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
2447
| ----------------------------------------- function or associated item `foo` not found for this struct
2548
|
2649
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
27-
--> $DIR/issue-62742.rs:28:20
50+
--> $DIR/issue-62742.rs:30:20
2851
|
2952
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
3053
| ^^^^^^ --------------
3154
| |
3255
| unsatisfied trait bound introduced here
3356
note: the trait `Raw` must be implemented
34-
--> $DIR/issue-62742.rs:12:1
57+
--> $DIR/issue-62742.rs:14:1
3558
|
3659
LL | pub trait Raw<T: ?Sized> {
3760
| ^^^^^^^^^^^^^^^^^^^^^^^^
3861

3962
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
40-
--> $DIR/issue-62742.rs:6:5
63+
--> $DIR/issue-62742.rs:8:5
4164
|
4265
LL | WrongImpl::<()>::foo(0i32);
4366
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
4467
|
4568
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
4669
= help: for that trait implementation, expected `[()]`, found `()`
4770
note: required by a bound in `SafeImpl`
48-
--> $DIR/issue-62742.rs:26:35
71+
--> $DIR/issue-62742.rs:28:35
4972
|
5073
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
5174
| ^^^^^^ required by this bound in `SafeImpl`
5275

53-
error: aborting due to 3 previous errors
76+
error: aborting due to 5 previous errors
5477

5578
Some errors have detailed explanations: E0277, E0599.
5679
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)