Description
A common problem I run into is that I add type annotations to into
where it should really be on the Into
trait instead. The error messages given for this are not helpful because they don't suggest adding type annotations to the Trait and then using UFCS instead of method syntax.
So what happens is that I write my code thinking rustc
can figure out the types, but it fails. A rough example is as follows (on play.rust-lang.org):
struct Y {}
impl Y {
pub fn new() -> Self {
Y{}
}
}
impl Into<u32> for Y {
fn into(self) -> u32 {
0u32
}
}
fn some_func(d: u32) {}
fn main() {
let y = Y::new();
let x = y.into() * 512u32;
some_func(x)
}
So I think that rustc
could infer all the types here, but it fails with:
error[E0283]: type annotations required: cannot resolve `Y: std::convert::Into<_>`
--> <anon>:20:15
|
20 | let x = y.into() * 512u32;
| ^^^^
Okay, that's fine, I can add some type annotations then. Now I only frequently work with type annotations on functions, so forgetting that the type annotation for Into
is on the trait and not the function, I replace the let x...
line above with let x = y.into::<u32>() * 512u32;
(on play.rust-lang.org) and get the following error:
error[E0035]: does not take type parameters
--> <anon>:20:15
|
20 | let x = y.into::<u32>() * 512u32;
| ^^^^ called with unneeded type parameters
Another thing I end up trying is to explicitly specify the type of x
by changing the let x...
line to let x: u32 = y.into() * 512u32;
, but you get the same initial error (E0283).
So a correct solution to this problem is to add the type annotations to Into
like so let x = Into::<u32>::into(y) * 512u32;
So my proposal here is twofold: 1) allow type inference to work for this example (which is quite reminiscent of code that I write) and 2) improve both E0283 and E0035.
For point 2, I think it would be possible to detect this exact situation and specify the correct solution.If the compiler sees type annotations on a function that doesn't have any, check the trait it's from and see if the trait itself takes type parameters. You could ignore the number of parameters specified to make this simpler and change E0035 to have help text at the bottom like:
error[E0035]: `into()` does not take type parameters
--> <anon>:20:15
|
20 | let x = y.into::<u32>() * 512u32;
| ^^^^ called with unneeded type parameters
|
= help: Did you mean to specify type parameters to the trait `Into` instead?
Possibly try instead `Into::<u32>::into(y)`
Something similar can be done for E0283. I don't know if there's a way that the compiler could tell if a type annotation on the output would work or if it has to be an input type annotation on the right-hand side, but I think defaulting to specifying the type directly would be the right solution anyways. Again I think the heuristic should be if there is a function that doesn't have a type annotation but its trait does then it should add help text to the error similar to that for E0035:
error[E0283]: type annotations required: cannot resolve `Y: std::convert::Into<_>`
--> <anon>:20:15
|
20 | let x = y.into() * 512u32;
| ^^^^
|
= help: Specify the type for `y.into()` like `Into::<XXX>::into(y)`, substituting the desired
type for XXX.
Note: These examples were run on rustc 1.17.0 (56124baa9 2017-04-24)