Description
affected test
- tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
trait Id {
type This: ?Sized;
}
trait Trait {
type Assoc: Id<This: Copy>;
}
fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
where
T::Assoc: Id<This = T::Assoc>,
{
(x, x)
}
This passes with the new solver, but not the old.
The reason is annoying subtle!
In the new solver computing alias bounds looks at all item bounds of the alias: https://github.com/rust-lang/rust/blob/cd805f09ffbfa3896c8f50a619de9b67e1d9f3c3/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs#L583-L593
In the old solver computing alias bounds only looks at item_super_predicates
in the first step: https://github.com/rust-lang/rust/blob/cd805f09ffbfa3896c8f50a619de9b67e1d9f3c3/compiler/rustc_trait_selection/src/traits/select/mod.rs#L1617-L1625
When proving T::Assoc: Copy
only the new solver therefore considers the item bound <T::Assoc as Id>::This: Copy
. It is then able to normalize <T::Assoc as Id>::This
to T::Assoc
, allowing us to prove the goal.
We're only able to do this, if there's a projection clause in the ParamEnv
or in the item bounds of our associated type:
trait Id {
type This: ?Sized;
}
impl<T: ?Sized> Id for T {
type This = T;
}
trait Normalize: Id<This = Self> {}
trait Trait {
type Assoc: Id<This: Copy> + Normalize;
}
fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
(x, x)
}
fn main() {}
As we can definitely use the item bound to prove T::Assoc: Id
, we cannot use an impl to normalize the <T::Assoc as Id>::This
, instead treating this associated type as rigid. The following does not compile:
trait Id {
type This: ?Sized;
}
impl<T: ?Sized> Id for T {
type This = T;
}
trait Trait {
type Assoc: Id<This: Copy>;
}
fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc) {
(x, x) //~ERROR use of moved value: `x`
}
fn main() {}
Metadata
Metadata
Assignees
Type
Projects
Status