-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
MVCE:
trait Trait<T> {
fn call_me(&self, x: T) {}
}
impl<T> Trait<u32> for T {}
impl<T> Trait<i32> for T {}
fn bug<T: Trait<U>, U>(x: T) {
x.call_me(1u32);
//~^ ERROR mismatched types
}
This is due to the fact that we prefer where-bounds over impls, even if the where-bounds have unnecessary inference constraints.
I stumbled upon this trying to write a function that generically takes a range (or something else with which str
can be indexed), and slices a str with that range. I got that to work, this bug comes into play when the str is produced by slicing another string with a RangeFrom
or another concrete type (in the same function).
Here's a simpler (no lifetimes, no associated types) and self-contained example (playpen):
trait Frobnicate<I> {
fn frob(&self, i: I) -> Self;
}
struct Thing;
struct IA;
struct IB;
impl Frobnicate<IA> for Thing {
fn frob(&self, _i: IA) -> Thing {
Thing
}
}
impl Frobnicate<IB> for Thing {
fn frob(&self, _i: IB) -> Thing {
Thing
}
}
fn delegate_frob<I>(t: Thing, i: I) -> Thing
where
Thing: Frobnicate<I>,
{
let t2: Thing = t.frob(IA);
t2.frob(i)
}
This seems innocent enough. There's a impl Frobnicate<IA> for Thing
, so the .frob(IA)
call should work, and it's known to return Thing
again, so via the where
clause the .frob(i)
call is good as well. However, I get this error message:
error[E0308]: mismatched types
--> src/main.rs:26:28
|
22 | fn delegate_frob<I>(t: Thing, i: I) -> Thing
| - expected this type parameter
...
26 | let t2: Thing = t.frob(IA);
| ---- ^^ expected type parameter `I`, found `IA`
| |
| arguments to this method are incorrect
|
= note: expected type parameter `I`
found struct `IA`
note: method defined here
--> src/main.rs:2:8
|
2 | fn frob(&self, i: I) -> Self;
| ^^^^ -
It appears that the where clause makes the compiler forget that there are other impls.
Adding a Thing : Frobnicate<IA>
bound only makes the compiler (rightly) complain that that's not a bound at all, since it doesn't involve any type parameters.
UFCS makes it compile, though:
let t2: Thing = <Thing as Frobnicate<IA>>::frob(&t, IA);
Edit: Besides playpen, I can also reproduce this locally:
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
binary: rustc
commit-hash: 9854143cba679834bc4ef932858cd5303f015a0e
commit-date: 2015-04-02
build-date: 2015-04-02
host: x86_64-pc-windows-gnu
release: 1.0.0-beta
But I already noticed it a couple of weeks ago, so it can't be a recent regression.