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:
lcnr 2024-01-15 11:47:53 +01:00
parent 91535ad026
commit f392a870e9
4 changed files with 102 additions and 96 deletions

View File

@ -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 where
F: FnOnce(u32) -> Ty<'tcx>, F: FnOnce(u32) -> Ty<'tcx>,
{ {
if let Some(ty) = opt_ty { match input {
return ty.fold_with(self); Ok(ty) => ty.fold_with(self),
} Err(key) => match self.ty_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
match self.ty_freshen_map.entry(key) { Entry::Vacant(entry) => {
Entry::Occupied(entry) => *entry.get(), let index = self.ty_freshen_count;
Entry::Vacant(entry) => { self.ty_freshen_count += 1;
let index = self.ty_freshen_count; let t = mk_fresh(index);
self.ty_freshen_count += 1; entry.insert(t);
let t = mk_fresh(index); t
entry.insert(t); }
t },
}
} }
} }
fn freshen_const<F>( fn freshen_const<F>(
&mut self, &mut self,
opt_ct: Option<ty::Const<'tcx>>, input: Result<ty::Const<'tcx>, ty::InferConst>,
key: ty::InferConst,
freshener: F, freshener: F,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> ty::Const<'tcx> ) -> ty::Const<'tcx>
where where
F: FnOnce(u32) -> ty::InferConst, F: FnOnce(u32) -> ty::InferConst,
{ {
if let Some(ct) = opt_ct { match input {
return ct.fold_with(self); Ok(ct) => ct.fold_with(self),
} Err(key) => match self.const_freshen_map.entry(key) {
Entry::Occupied(entry) => *entry.get(),
match self.const_freshen_map.entry(key) { Entry::Vacant(entry) => {
Entry::Occupied(entry) => *entry.get(), let index = self.const_freshen_count;
Entry::Vacant(entry) => { self.const_freshen_count += 1;
let index = self.const_freshen_count; let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty);
self.const_freshen_count += 1; entry.insert(ct);
let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty); ct
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> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() { match ct.kind() {
ty::ConstKind::Infer(ty::InferConst::Var(v)) => { ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
let opt_ct = let mut inner = self.infcx.inner.borrow_mut();
self.infcx.inner.borrow_mut().const_unification_table().probe_value(v).known(); let input =
self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) 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)) => { ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => {
let opt_ct = let mut inner = self.infcx.inner.borrow_mut();
self.infcx.inner.borrow_mut().effect_unification_table().probe_value(v).known(); let input =
self.freshen_const( inner.effect_unification_table().probe_value(v).known().ok_or_else(|| {
opt_ct, ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid)
ty::InferConst::EffectVar(v), });
ty::InferConst::Fresh, drop(inner);
ct.ty(), self.freshen_const(input, ty::InferConst::Fresh, ct.ty())
)
} }
ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
if i >= self.const_freshen_count { 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>> { fn fold_infer_ty(&mut self, v: ty::InferTy) -> Option<Ty<'tcx>> {
match v { match v {
ty::TyVar(v) => { ty::TyVar(v) => {
let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); let mut inner = self.infcx.inner.borrow_mut();
Some(self.freshen_ty(opt_ty, ty::TyVar(v), |n| Ty::new_fresh(self.infcx.tcx, n))) 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( ty::IntVar(v) => {
self.freshen_ty( let mut inner = self.infcx.inner.borrow_mut();
self.infcx let input = inner
.inner .int_unification_table()
.borrow_mut() .probe_value(v)
.int_unification_table() .map(|v| v.to_type(self.infcx.tcx))
.probe_value(v) .ok_or_else(|| ty::IntVar(inner.int_unification_table().find(v)));
.map(|v| v.to_type(self.infcx.tcx)), drop(inner);
ty::IntVar(v), Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n)))
|n| Ty::new_fresh_int(self.infcx.tcx, n), }
),
),
ty::FloatVar(v) => Some( ty::FloatVar(v) => {
self.freshen_ty( let mut inner = self.infcx.inner.borrow_mut();
self.infcx let input = inner
.inner .float_unification_table()
.borrow_mut() .probe_value(v)
.float_unification_table() .map(|v| v.to_type(self.infcx.tcx))
.probe_value(v) .ok_or_else(|| ty::FloatVar(inner.float_unification_table().find(v)));
.map(|v| v.to_type(self.infcx.tcx)), drop(inner);
ty::FloatVar(v), Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n)))
|n| Ty::new_fresh_float(self.infcx.tcx, n), }
),
),
ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => { ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct) => {
if ct >= self.ty_freshen_count { if ct >= self.ty_freshen_count {

View File

@ -40,7 +40,6 @@ use rustc_middle::dep_graph::DepNodeIndex;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::_match::MatchAgainstFreshVars;
use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; 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) { match self.match_impl(impl_def_id, impl_trait_header, obligation) {
Ok(args) => args, Ok(args) => args,
Err(()) => { Err(()) => {
// FIXME: A rematch may fail when a candidate cache hit occurs let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
// on the freshened form of the trait predicate, but the match bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not")
// 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![] }
} }
} }
} }

View File

@ -3,6 +3,8 @@ use std::marker::PhantomData;
fn _alias_check() { fn _alias_check() {
WrongImpl::foo(0i32); 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
//~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied
WrongImpl::<()>::foo(0i32); WrongImpl::<()>::foo(0i32);
//~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied
//~| ERROR trait bounds were not satisfied //~| ERROR trait bounds were not satisfied

View File

@ -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 error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied
--> $DIR/issue-62742.rs:4:5 --> $DIR/issue-62742.rs:4:5
| |
@ -6,13 +21,21 @@ LL | WrongImpl::foo(0i32);
| |
= help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>`
note: required by a bound in `SafeImpl` 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)>); LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl` | ^^^^^^ 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 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); LL | WrongImpl::<()>::foo(0i32);
| ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds | ^^^ 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 | ----------------------------------------- function or associated item `foo` not found for this struct
| |
note: trait bound `RawImpl<()>: Raw<()>` was not satisfied 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> { LL | impl<T: ?Sized, A: Raw<T>> SafeImpl<T, A> {
| ^^^^^^ -------------- | ^^^^^^ --------------
| | | |
| unsatisfied trait bound introduced here | unsatisfied trait bound introduced here
note: the trait `Raw` must be implemented 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> { LL | pub trait Raw<T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied 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); LL | WrongImpl::<()>::foo(0i32);
| ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` | ^^^^^^^^^^^^^^^ 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: the trait `Raw<[()]>` is implemented for `RawImpl<()>`
= help: for that trait implementation, expected `[()]`, found `()` = help: for that trait implementation, expected `[()]`, found `()`
note: required by a bound in `SafeImpl` 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)>); LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
| ^^^^^^ required by this bound in `SafeImpl` | ^^^^^^ 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. Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`. For more information about an error, try `rustc --explain E0277`.