Open d0sboots opened 1 year ago
The suggestion is syntactically incorrect. @rustbot label A-suggestion-diagnostics D-incorrect
Naively, one one expect that the requirement of array access being usize means an into() would work here. Clearly, that's not the case but I'm still not sure why.
usize
is allowed to be 16 bits wide, so it can't implement From<i32>
. It would be nice if the compiler could suggest using try_into
instead, but I don't know how feasible that is.
usize
is allowed to be 16 bits wide, so it can't implementFrom<i32>
.
Oof. I actually already knew that, since I have a bunch of as
coercions elsewhere in my code. (It's not just because of 16-bit machines - i32
can't be converted to u32
transparently.)
However, that's not the whole explanation. u8
, which does convert to usize
, doesn't work either (but it has much better diagnostics):
fn main() {
let arr: [u32; 3] = [0, 1, 2];
let idx = 0u8;
let val: u32 = arr[idx.into()];
println!("{}", val);
}
error[[E0282]](https://doc.rust-lang.org/stable/error-index.html#E0282): type annotations needed
--> src/main.rs:4:28
|
4 | let val: u32 = arr[idx.into()];
| ^^^^
|
help: try using a fully qualified path to specify the expected types
|
4 | let val: u32 = arr[<u8 as Into<T>>::into(idx)];
| ++++++++++++++++++++++ ~
For more information about this error, try `rustc --explain E0282`.
(Also, for some reason usize
doesn't implement From<i8>
, but that's a different issue.)
It seems like this issue is already fixed on nightly:
error[E0282]: type annotations needed
--> src/main.rs:4:28
|
4 | println!("{}", arr[idx.into()]);
| ^^^^
|
help: try using a fully qualified path to specify the expected types
|
4 | println!("{}", arr[<i32 as Into<T>>::into(idx)]);
| +++++++++++++++++++++++ ~
It seems like this issue is already fixed on nightly:
error[E0282]: type annotations needed --> src/main.rs:4:28 | 4 | println!("{}", arr[idx.into()]); | ^^^^ | help: try using a fully qualified path to specify the expected types | 4 | println!("{}", arr[<i32 as Into<T>>::into(idx)]); | +++++++++++++++++++++++ ~
Not completely, that's just a different rearrangement of syntax that doesn't compile:
Compiling playground v0.0.1 (/playground)
error[[E0412]](https://doc.rust-lang.org/nightly/error-index.html#E0412): cannot find type `T` in this scope
--> src/main.rs:4:37
|
4 | println!("{}", arr[<i32 as Into<T>>::into(idx)]);
| ^ not found in this scope
For more information about this error, try `rustc --explain E0412`.
error: could not compile `playground` due to previous error
@d0sboots the compiler is giving you the syntax that you can use to specify what you're turning into, but it can't guess which type you want to convert to. Until #114811 we weren't showing you the full list because it was too long, but after it the output is:
error[E0283]: type annotations needed
--> f71.rs:4:28
|
4 | let val: u32 = arr[idx.into()];
| ^^^^
|
= note: multiple `impl`s satisfying `_: From<u8>` found in the following crates: `core`, `std`:
- impl From<u8> for AtomicU8;
- impl From<u8> for ExitCode;
- impl From<u8> for char;
- impl From<u8> for f32;
- impl From<u8> for f64;
- impl From<u8> for i128;
- impl From<u8> for i16;
- impl From<u8> for i32;
- impl From<u8> for i64;
- impl From<u8> for isize;
- impl From<u8> for std::sys::unix::process::process_common::ExitCode;
- impl From<u8> for u128;
- impl From<u8> for u16;
- impl From<u8> for u32;
- impl From<u8> for u64;
- impl From<u8> for usize;
= note: required for `u8` to implement `Into<_>`
help: try using a fully qualified path to specify the expected types
|
4 | let val: u32 = arr[<u8 as Into<T>>::into(idx)];
| ++++++++++++++++++++++ ~
You need to substitute T
with usize
to make your code work.
The original report with the mentioned PR adds the list of impls to the output:
error[E0283]: type annotations needed
--> f71.rs:4:28
|
4 | println!("{}", arr[idx.into()]);
| ^^^^
|
= note: multiple `impl`s satisfying `_: From<i32>` found in the following crates: `core`, `std`:
- impl From<i32> for AtomicI32;
- impl From<i32> for f64;
- impl From<i32> for i128;
- impl From<i32> for i64;
- impl From<i32> for std::sys::unix::process::process_inner::ExitStatus;
= note: required for `i32` to implement `Into<_>`
help: try using a fully qualified path to specify the expected types
|
4 | println!("{}", arr[<i32 as Into<T>>::into(idx)]);
| +++++++++++++++++++++++ ~
Only outstanding work is to have rustc understand From
/Into
impls specifically and use the appropriate types in the suggestion.
So, there's one thing I still don't understand with this. Array indexing is always a usize
context, right? So why is it showing the full list of all From
impls for u8
, and unable to infer the correct destination type?
Because of this, the real code change here (for the non-working code sample) IMO is to assign to a temporary variable, so that the type inference works better.
Correct, the indexing operation doesn't (today) influence inference in the way that we would need for this to work.
Code
Current output
Desired output
I'm too new to Rust to say exactly, but:
idx.into()
expression, not the outer expression it is highlighting::<T>
, which is not syntactically valid hereRationale and extra context
Naively, one one expect that the requirement of array access being
usize
means aninto()
would work here. Clearly, that's not the case but I'm still not sure why.Other cases
still gives bad advice, although less catastrophically:
Only when you take that bad advice, but with an explicit type instead of _, do you get a useful message:
Anything else?
No response