Why does Rust fail to pick the right trait in this case? - rust

Consider the following code:
use std::ops::Add;
trait Trait
where Self::Assoc: Add<Self::Assoc, Output=Self::Assoc>
+ for <'a> Add<&'a Self::Assoc, Output=Self::Assoc>
{
type Assoc;
fn get(&self) -> Self::Assoc;
}
fn add1<T: Trait>(x: T, y: T) -> T::Assoc {
x.get() + y.get()
}
This fails to compile with:
error[E0308]: mismatched types
--> src/lib.rs:12:15
|
12 | x.get() + y.get()
| ^^^^^^^
| |
| expected reference, found associated type
| help: consider borrowing here: `&y.get()`
|
= note: expected reference `&<T as Trait>::Assoc`
found associated type `<T as Trait>::Assoc`
I'm able to work around the issue by explicitly specifying what trait I want to use:
fn add2<T: Trait>(x: T, y: T) -> T::Assoc {
<T::Assoc as Add<T::Assoc>>::add(x.get(), y.get())
}
But I'm wondering: why is this happening? Also, is there any more compact work around?
Note that the order of the trait bounds matters. If I change them to:
where Self::Assoc: for <'a> Add<&'a Self::Assoc, Output=Self::Assoc>
+ Add<Self::Assoc, Output=Self::Assoc>
... then add1 compiles fine, but this fails:
fn add3<T: Trait>(x: T, y: T) -> T::Assoc {
x.get() + &y.get()
}
Link to playground

Related

Blanket implementation returning reference fails with "the parameter type `T` may not live long enough"

Compilation of this snippet:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S, T> OnBase for S
where
S: Base<T = dyn OnBase<T = T>>,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A {}
Fails with:
error[E0311]: the parameter type `T` may not live long enough
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
|
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
--> src/blanket_with_ref.rs:16:14
|
16 | fn get_a(&self) -> &A {
| ^^^^^
note: ...so that the type `T` will meet its required lifetime bounds
--> src/blanket_with_ref.rs:17:9
|
17 | self.get_p().get_a()
| ^^^^^^^^^^^^
help: consider adding an explicit lifetime bound...
|
14 | impl <S, T: 'a> OnBase for S where S:Base<T=dyn OnBase<T=T>> {
| ++++
I vaguely comprehend that I must somehow tell it that lifetimes of Base and OnBase should be same but even if I add 'a to all traits and refrences it keeps failing.
Is it possible to somehow make it compile?
P.S. - it works if get_a returns plain A.
pps - in the real app it should be a kind of a strategy delegating to whatever impl it encapsulates
playground
This is probably what you actually want, instead of T = dyn OnBase<T = T>:
trait Base {
type T;
fn get_p(&self) -> &Self::T;
}
trait OnBase: Base {
fn get_a(&self) -> &A;
}
impl<S> OnBase for S
where
S: Base,
<S as Base>::T: OnBase,
{
fn get_a(&self) -> &A {
self.get_p().get_a()
}
}
struct A;
I'm not sure what purpose OnBase: Base serves, though. If OnBase is already Base, then why do any of this? And what should it return in get_p? With the current layout, it's really easy to get caught up in an infinite get_a recursion.

Rust compiler is hitting trait evaluation recursion limit trying to check for trait implementations on types unrelated to my code

I have constructed the following example. It is at least approximately minimal.
use std::ops::Mul;
trait Muls<Rhs>:
Mul<Rhs, Output = <Self as Muls<Rhs>>::Output>
+ for<'a> Mul<&'a Rhs, Output = <Self as Muls<Rhs>>::Output>
{
type Output;
}
impl<T, R, O> Muls<R> for T
where
T: Mul<R, Output = O>,
T: for<'a> Mul<&'a R, Output = O>,
{
type Output = O;
}
trait ScalarMulCore {
type Scalar;
fn scalar_mul(&self, rhs: &Self::Scalar) -> Self;
fn scalar_mul_in_place(&mut self, rhs: &Self::Scalar);
}
struct Wrap<T> {
x: T,
}
impl<T> ScalarMulCore for Wrap<T>
where
T: Muls<T, Output = T>,
for<'a> &'a T: Muls<T, Output = T>,
{
type Scalar = T;
fn scalar_mul(&self, rhs: &Self::Scalar) -> Self {
Self { x: (&self.x) * rhs }
}
fn scalar_mul_in_place(&mut self, rhs: &Self::Scalar) {
self.x = (&self.x) * rhs;
}
}
impl<T> Mul<<Wrap<T> as ScalarMulCore>::Scalar> for Wrap<T>
where
Wrap<T>: ScalarMulCore,
{
type Output = Wrap<T>;
fn mul(mut self, rhs: <Wrap<T> as ScalarMulCore>::Scalar) -> Self::Output {
<Wrap<T> as ScalarMulCore>::scalar_mul_in_place(&mut self, &rhs);
self
}
}
impl<T> Mul<<Wrap<T> as ScalarMulCore>::Scalar> for &Wrap<T>
where
Wrap<T>: ScalarMulCore,
{
type Output = Wrap<T>;
fn mul(self, rhs: <Wrap<T> as ScalarMulCore>::Scalar) -> Self::Output {
<Wrap<T> as ScalarMulCore>::scalar_mul(self, &rhs)
}
}
fn main() {
let a = Wrap::<isize> { x: 2 };
let b: isize = 3;
assert_eq!((a * b).x, 6);
}
Trying to compile this produces the following error message:
Compiling mwe v0.1.0 (/home/zistack/Projects/mwe)
error[E0275]: overflow evaluating the requirement `for<'a> &'a Simd<_, _>: Mul<Simd<_, _>>`
--> src/main.rs:47:56
|
47 | impl <T> Mul <<Wrap <T> as ScalarMulCore>::Scalar> for Wrap <T>
| ^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mwe`)
note: required for `&'a Simd<_, _>` to implement `for<'a> Muls<Simd<_, _>>`
--> src/main.rs:10:16
|
10 | impl <T, R, O> Muls <R> for T
| ^^^^^^^^ ^
11 | where
12 | T: Mul <R, Output = O>,
| ---------- unsatisfied trait bound introduced here
note: required for `Wrap<Simd<_, _>>` to implement `ScalarMulCore`
--> src/main.rs:29:10
|
29 | impl <T> ScalarMulCore for Wrap <T>
| ^^^^^^^^^^^^^ ^^^^^^^^
...
32 | for <'a> &'a T: Muls <T, Output = T>
| ---------- unsatisfied trait bound introduced here
= note: 62 redundant requirements hidden
= note: required for `Wrap<_>` to implement `ScalarMulCore`
error[E0275]: overflow evaluating the requirement `for<'a> &'a Simd<_, _>: Mul<Simd<_, _>>`
--> src/main.rs:59:56
|
59 | impl <T> Mul <<Wrap <T> as ScalarMulCore>::Scalar> for &Wrap <T>
| ^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mwe`)
note: required for `&'a Simd<_, _>` to implement `for<'a> Muls<Simd<_, _>>`
--> src/main.rs:10:16
|
10 | impl <T, R, O> Muls <R> for T
| ^^^^^^^^ ^
11 | where
12 | T: Mul <R, Output = O>,
| ---------- unsatisfied trait bound introduced here
note: required for `Wrap<Simd<_, _>>` to implement `ScalarMulCore`
--> src/main.rs:29:10
|
29 | impl <T> ScalarMulCore for Wrap <T>
| ^^^^^^^^^^^^^ ^^^^^^^^
...
32 | for <'a> &'a T: Muls <T, Output = T>
| ---------- unsatisfied trait bound introduced here
= note: 62 redundant requirements hidden
= note: required for `Wrap<_>` to implement `ScalarMulCore`
For more information about this error, try `rustc --explain E0275`.
error: could not compile `mwe` due to 2 previous errors
I am using the nightly build.
The this example is pretty close to some real code that I want to write, and functionally identical to some test code that has been giving me some trouble. Strangely enough, if you comment out the second implementation of Mul, it compiles without issue. I cannot get away with doing this in my real code.
Why on earth is rustc trying to see if Wrap <Simd <_, _>> implements ScalarMulCore? I never asked for that type. Even if I did, why would that cause rustc to hit the recursion limit? Also, why is rustc only doing this when I attempt to additionally implement Mul for &Wrap <T>?
I know I'm linking to my own comment here, but it would appear that this behavior is a long-standing bug in the rust compiler.

Convert vector of type A to type B where A is convertible to B

I'm learning rust, and one of the most basic things I want to do is to take one vector of homogenous type A which is convertible to another type B (since From<> is implemented and thus we can use .into()). When I tried running the below I got the following:
struct A {
x: String
}
struct B {
x: String
}
impl From<A> for B {
fn from(a: A) -> Self {
B { x: a.x }
}
}
impl B {
pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self {
B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
}
}
fn main() {
...
}
I got:
error[E0277]: the trait bound `B: From<T>` is not satisfied
--> src/main.rs:17:41
|
17 | B { x: v.iter().map(|e| B::from(e.clone()).x).collect::<Vec<String>>().join(" ") }
| ------- ^^^^^^^^^ the trait `From<T>` is not implemented for `B`
| |
| required by a bound introduced by this call
|
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
15 | impl B where B: From<T> {
| ++++++++++++++++
I originally tried it without the clone(), but thought that it didn't accept references:
...
impl B {
pub fn from_many<T: Into<B>>(v: Vec<T>) -> Self {
B { x: v.iter().map(|e| B::from(e).x).collect::<Vec<String>>().join(" ") }
}
}
...
which yielded:
error[E0277]: the trait bound `B: From<&T>` is not satisfied
--> src/main.rs:17:41
|
17 | B { x: v.iter().map(|e| B::from(e).x).collect::<Vec<String>>().join(" ") }
| ------- ^ the trait `From<&T>` is not implemented for `B`
| |
| required by a bound introduced by this call
|
= help: the trait `From<A>` is implemented for `B`
I'm not asking for an arbitrary T here, I'm asking for T which has Into<B> for T defined (in this case, I believe it's defined since I defined the From trait). Did I do something stupid here?
You're missing a very simple but easy to miss fact: if you have a From<T> for U implementation you automatically have a Into<U> for T implementation, but the opposite is not true. Thus, if by generics you require T: Into<B> (which is the right thing to do since it is more generic than B: From<T>), you need to use .into() and not B::from():
impl B {
pub fn from_many<T: Into<B> + Clone>(v: Vec<T>) -> Self {
B { x: v.iter().map(|e| e.clone().into().x).collect::<Vec<String>>().join(" ") }
}
}
Another, but unrelated, thing you're missing is that since you have an owned Vec<T> you can use into_iter() and then you don't need to .clone():
impl B {
pub fn from_many<T: Into<B>>(v: Vec<T>) -> Self {
B { x: v.into_iter().map(|e| e.into().x).collect::<Vec<String>>().join(" ") }
}
}

Why does `|_| 1` not meet lifetime requirements

I have the following trait and generic implementation for Fn:
trait Provider<'a> {
type Out;
fn get(&'a self, state: &State) -> Self::Out;
}
impl<'a, F, T> Provider<'a> for F
where
F: Fn(&State) -> T,
{
type Out = T;
fn get(&'a self, state: &State) -> T {
self(state)
}
}
Now, I have some code that wants a for<'a> Provider<'a, Out = usize>. However, the most simple closure, |_| 1, does not qualify and instead provides this error message which I don't understand:
fn assert_usize_provider<P>(_: P)
where
P: for<'a> Provider<'a, Out = usize>,
{
}
fn main() {
assert_usize_provider(|_| 1);
}
error[E0308]: mismatched types
--> src/main.rs:27:5
|
27 | assert_usize_provider(|_| 1);
| ^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `FnOnce<(&State,)>`
found type `FnOnce<(&State,)>`
note: this closure does not fulfill the lifetime requirements
--> src/main.rs:27:27
|
27 | assert_usize_provider(|_| 1);
| ^^^^^
note: the lifetime requirement is introduced here
--> src/main.rs:22:29
|
22 | P: for<'a> Provider<'a, Out = usize>,
| ^^^^^^^^^^^
Playground link
Can someone explain what that error message means and how to get this code working?
I don't know why inference does not work in this case but you can add type annotation to get the code working.
assert_usize_provider(|_ : &State| 1);

No implementation for `T + T`

In this following example:
trait AddStrategy<T> {
fn do_calc(&mut self, a: T, b: T) -> &Adder<T>;
}
struct Adder<T> {
val: T,
}
use std::ops::Add;
fn add<T: Add>(a: T, b: T) -> T::Output {
a + b
}
impl<T> AddStrategy<T> for Adder<T> {
fn do_calc(&mut self, a: T, b: T) -> &Adder<T> {
let x = add(a, b); //<---error: no implementation for `T + T`
self.val = x;
self
}
}
I'm getting error:
error[E0277]: cannot add `T` to `T`
--> src/lib.rs:15:17
|
9 | fn add<T: Add>(a: T, b: T) -> T::Output {
| --- --- required by this bound in `add`
...
13 | impl<T> AddStrategy<T> for Adder<T> {
| - help: consider restricting this bound: `T: std::ops::Add`
14 | fn do_calc(&mut self, a: T, b: T) -> &Adder<T> {
15 | let x = add(a, b); //<---error: no implementation for `T + T`
| ^^^ no implementation for `T + T`
|
= help: the trait `std::ops::Add` is not implemented for `T`
error[E0277]: cannot add `T` to `T`
--> src/lib.rs:15:17
|
13 | impl<T> AddStrategy<T> for Adder<T> {
| - help: consider restricting this bound: `T: std::ops::Add`
14 | fn do_calc(&mut self, a: T, b: T) -> &Adder<T> {
15 | let x = add(a, b); //<---error: no implementation for `T + T`
| ^^^^^^^^^ no implementation for `T + T`
|
= help: the trait `std::ops::Add` is not implemented for `T`
What is wrong in this code?
I fixed your example so you can find your working solution in this playground.
While fn add<T: Add>(a: T, b: T) has the trait bound Add for type T, AddStrategy which calls it does not have the same trait bound: anything (sized) can be used by AddStrategy. Therefore the Rust compiler tells you "I'm sorry, but you're trying to call add on something which isn't guaranteed to be add-able".
So the first thing you have to do is to bound AddStrategy to Add:
trait AddStrategy<T: Add> { // <--- T: Add
}
And it sounds pretty good since AddStrategy is about to add values.
The same with trait implementation for Adder:
impl<T: Add> AddStrategy<T> for Adder<T> { // <--- T: Add
Then you have to fix Adder because it's about to store the output from the add function which has type of T::Output, and Output is an item type of Add trait:
struct Adder<T: Add> { // <--- Now Adder is aware about T characteristics
val: T::Output, // <--- so you can use `T::Output` from the `Add` trait
}
And so on: basically, define traits for types and it allows you to fix errors step by step until you make everything explicit.
An alternative (which doesn't seem useful here but there you go) is that instead of Adder being bound to Add you could implement AddStrategy if and only if Adder is working with Add values: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d83fd48f88eec68346a3d633e8a7f72c

Resources