Skip to content

Commit

Permalink
freshen: resolve root vars
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lcnr committed Jan 15, 2024
1 parent f5c56ec commit d99a07d
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 106 deletions.
146 changes: 70 additions & 76 deletions compiler/rustc_infer/src/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
},
}
}
}
Expand Down Expand Up @@ -146,30 +143,25 @@ 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)
.val
.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).val.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()
let mut inner = self.infcx.inner.borrow_mut();
let input = inner
.effect_unification_table()
.probe_value(v)
.map(|effect| effect.as_const(self.infcx.tcx));
self.freshen_const(
opt_ct,
ty::InferConst::EffectVar(v),
ty::InferConst::Fresh,
ct.ty(),
)
.map(|effect| effect.as_const(self.infcx.tcx))
.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 {
Expand Down Expand Up @@ -202,35 +194,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::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::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) => {
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 {
Expand Down
25 changes: 2 additions & 23 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -2417,28 +2416,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
match self.match_impl(impl_def_id, impl_trait_ref, 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")
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/impl-trait/issues/issue-62742.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 30 additions & 7 deletions tests/ui/impl-trait/issues/issue-62742.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -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
Expand All @@ -24,33 +47,33 @@ 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<()>`
|
= 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`.

0 comments on commit d99a07d

Please sign in to comment.