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.
This commit is contained in:
parent
91535ad026
commit
f392a870e9
@ -56,49 +56,46 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn freshen_ty<F>(&mut self, opt_ty: Option<Ty<'tcx>>, key: ty::InferTy, mk_fresh: F) -> Ty<'tcx>
|
||||
fn freshen_ty<F>(&mut self, input: Result<Ty<'tcx>, ty::InferTy>, mk_fresh: F) -> Ty<'tcx>
|
||||
where
|
||||
F: FnOnce(u32) -> Ty<'tcx>,
|
||||
{
|
||||
if let Some(ty) = opt_ty {
|
||||
return ty.fold_with(self);
|
||||
}
|
||||
|
||||
match self.ty_freshen_map.entry(key) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
let index = self.ty_freshen_count;
|
||||
self.ty_freshen_count += 1;
|
||||
let t = mk_fresh(index);
|
||||
entry.insert(t);
|
||||
t
|
||||
}
|
||||
match input {
|
||||
Ok(ty) => ty.fold_with(self),
|
||||
Err(key) => match self.ty_freshen_map.entry(key) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
let index = self.ty_freshen_count;
|
||||
self.ty_freshen_count += 1;
|
||||
let t = mk_fresh(index);
|
||||
entry.insert(t);
|
||||
t
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn freshen_const<F>(
|
||||
&mut self,
|
||||
opt_ct: Option<ty::Const<'tcx>>,
|
||||
key: ty::InferConst,
|
||||
input: Result<ty::Const<'tcx>, ty::InferConst>,
|
||||
freshener: F,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ty::Const<'tcx>
|
||||
where
|
||||
F: FnOnce(u32) -> ty::InferConst,
|
||||
{
|
||||
if let Some(ct) = opt_ct {
|
||||
return ct.fold_with(self);
|
||||
}
|
||||
|
||||
match self.const_freshen_map.entry(key) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
let index = self.const_freshen_count;
|
||||
self.const_freshen_count += 1;
|
||||
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
|
||||
entry.insert(ct);
|
||||
ct
|
||||
}
|
||||
match input {
|
||||
Ok(ct) => ct.fold_with(self),
|
||||
Err(key) => match self.const_freshen_map.entry(key) {
|
||||
Entry::Occupied(entry) => *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
let index = self.const_freshen_count;
|
||||
self.const_freshen_count += 1;
|
||||
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
|
||||
entry.insert(ct);
|
||||
ct
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,19 +143,22 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
|
||||
let opt_ct =
|
||||
self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known();
|
||||
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty())
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let input =
|
||||
inner.const_unification_table().probe_value(v).known().ok_or_else(|| {
|
||||
ty::InferConst::Var(inner.const_unification_table().find(v).vid)
|
||||
});
|
||||
drop(inner);
|
||||
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
|
||||
let opt_ct =
|
||||
self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known();
|
||||
self.freshen_const(
|
||||
opt_ct,
|
||||
ty::InferConst::EffectVar(v),
|
||||
ty::InferConst::Fresh,
|
||||
ct.ty(),
|
||||
)
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let input =
|
||||
inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
|
||||
ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
|
||||
});
|
||||
drop(inner);
|
||||
self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
|
||||
if i >= self.const_freshen_count {
|
||||
@ -191,35 +191,37 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
|
||||
fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
|
||||
match v {
|
||||
ty::TyVar(v) => {
|
||||
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known();
|
||||
Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n)))
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let input = inner
|
||||
.type_variables()
|
||||
.probe(v)
|
||||
.known()
|
||||
.ok_or_else(|| ty::TyVar(inner.type_variables().root_var(v)));
|
||||
drop(inner);
|
||||
Some(self.freshen_ty(input, |n| Ty::new_fresh(self.infcx.tcx, n)))
|
||||
}
|
||||
|
||||
ty::IntVar(v) => Some(
|
||||
self.freshen_ty(
|
||||
self.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.int_unification_table()
|
||||
.probe_value(v)
|
||||
.map(|v| v.to_type(self.infcx.tcx)),
|
||||
ty::IntVar(v),
|
||||
|n| Ty::new_fresh_int(self.infcx.tcx, n),
|
||||
),
|
||||
),
|
||||
ty::IntVar(v) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let input = inner
|
||||
.int_unification_table()
|
||||
.probe_value(v)
|
||||
.map(|v| v.to_type(self.infcx.tcx))
|
||||
.ok_or_else(|| ty::IntVar(inner.int_unification_table().find(v)));
|
||||
drop(inner);
|
||||
Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
|
||||
}
|
||||
|
||||
ty::FloatVar(v) => Some(
|
||||
self.freshen_ty(
|
||||
self.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.float_unification_table()
|
||||
.probe_value(v)
|
||||
.map(|v| v.to_type(self.infcx.tcx)),
|
||||
ty::FloatVar(v),
|
||||
|n| Ty::new_fresh_float(self.infcx.tcx, n),
|
||||
),
|
||||
),
|
||||
ty::FloatVar(v) => {
|
||||
let mut inner = self.infcx.inner.borrow_mut();
|
||||
let input = inner
|
||||
.float_unification_table()
|
||||
.probe_value(v)
|
||||
.map(|v| v.to_type(self.infcx.tcx))
|
||||
.ok_or_else(|| ty::FloatVar(inner.float_unification_table().find(v)));
|
||||
drop(inner);
|
||||
Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
|
||||
}
|
||||
|
||||
ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
|
||||
if ct >= self.ty_freshen_count {
|
||||
|
@ -40,7 +40,6 @@ use rustc_middle::dep_graph::DepNodeIndex;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::_match::MatchAgainstFreshVars;
|
||||
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
|
||||
use rustc_middle::ty::fold::BottomUpFolder;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||
@ -2435,28 +2434,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
match self.match_impl(impl_def_id, impl_trait_header, obligation) {
|
||||
Ok(args) => args,
|
||||
Err(()) => {
|
||||
// FIXME: A rematch may fail when a candidate cache hit occurs
|
||||
// on the freshened form of the trait predicate, but the match
|
||||
// fails for some reason that is not captured in the freshened
|
||||
// cache key. For example, equating an impl trait ref against
|
||||
// the placeholder trait ref may fail due the Generalizer relation
|
||||
// raising a CyclicalTy error due to a sub_root_var relation
|
||||
// for a variable being generalized...
|
||||
let guar = self.infcx.dcx().span_delayed_bug(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
"Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
|
||||
),
|
||||
);
|
||||
let value = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id);
|
||||
let err = Ty::new_error(self.tcx(), guar);
|
||||
let value = value.fold_with(&mut BottomUpFolder {
|
||||
tcx: self.tcx(),
|
||||
ty_op: |_| err,
|
||||
lt_op: |l| l,
|
||||
ct_op: |c| c,
|
||||
});
|
||||
Normalized { value, obligations: vec![] }
|
||||
let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
|
||||
bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ use std::marker::PhantomData;
|
||||
fn _alias_check() {
|
||||
WrongImpl::foo(0i32);
|
||||
//~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
WrongImpl::<()>::foo(0i32);
|
||||
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
|
||||
//~| ERROR trait bounds were not satisfied
|
||||
|
@ -1,3 +1,18 @@
|
||||
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
--> $DIR/issue-62742.rs:4:5
|
||||
|
|
||||
LL | WrongImpl::foo(0i32);
|
||||
| ^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
||||
|
|
||||
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
|
||||
note: required by a bound in `SafeImpl::<T, A>::foo`
|
||||
--> $DIR/issue-62742.rs:30:20
|
||||
|
|
||||
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
|
||||
| ^^^^^^ required by this bound in `SafeImpl::<T, A>::foo`
|
||||
LL | pub fn foo(value: A::Value) {}
|
||||
| --- required by a bound in this associated function
|
||||
|
||||
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
--> $DIR/issue-62742.rs:4:5
|
||||
|
|
||||
@ -6,13 +21,21 @@ LL | WrongImpl::foo(0i32);
|
||||
|
|
||||
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
|
||||
note: required by a bound in `SafeImpl`
|
||||
--> $DIR/issue-62742.rs:26:35
|
||||
--> $DIR/issue-62742.rs:28:35
|
||||
|
|
||||
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
|
||||
| ^^^^^^ required by this bound in `SafeImpl`
|
||||
|
||||
error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
|
||||
--> $DIR/issue-62742.rs:4:5
|
||||
|
|
||||
LL | WrongImpl::foo(0i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>`
|
||||
|
|
||||
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
|
||||
|
||||
error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied
|
||||
--> $DIR/issue-62742.rs:6:22
|
||||
--> $DIR/issue-62742.rs:8:22
|
||||
|
|
||||
LL | WrongImpl::<()>::foo(0i32);
|
||||
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds
|
||||
@ -24,20 +47,20 @@ LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
|
||||
| ----------------------------------------- function or associated item `foo` not found for this struct
|
||||
|
|
||||
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied
|
||||
--> $DIR/issue-62742.rs:28:20
|
||||
--> $DIR/issue-62742.rs:30:20
|
||||
|
|
||||
LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
|
||||
| ^^^^^^ --------------
|
||||
| |
|
||||
| unsatisfied trait bound introduced here
|
||||
note: the trait `Raw` must be implemented
|
||||
--> $DIR/issue-62742.rs:12:1
|
||||
--> $DIR/issue-62742.rs:14:1
|
||||
|
|
||||
LL | pub trait Raw<T: ?Sized> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied
|
||||
--> $DIR/issue-62742.rs:6:5
|
||||
--> $DIR/issue-62742.rs:8:5
|
||||
|
|
||||
LL | WrongImpl::<()>::foo(0i32);
|
||||
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>`
|
||||
@ -45,12 +68,12 @@ LL | WrongImpl::<()>::foo(0i32);
|
||||
= help: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
|
||||
= help: for that trait implementation, expected `[()]`, found `()`
|
||||
note: required by a bound in `SafeImpl`
|
||||
--> $DIR/issue-62742.rs:26:35
|
||||
--> $DIR/issue-62742.rs:28:35
|
||||
|
|
||||
LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
|
||||
| ^^^^^^ required by this bound in `SafeImpl`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0599.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user