Rust: Bad "Ambiguous Numeric Type" Recommendation from Compiler in for loop

Created on 21 Aug 2018  路  7Comments  路  Source: rust-lang/rust

The pow function cannot be called on an ambiguous numeric type. If pow is called on the variable of a for loop, the compiler's recommended solution to add a concrete numeric type does not compile.

Example code with ambiguous numeric type:

pub fn check() {
    for i in 0..1000 {
        println!("{}", i.pow(2));
    }
}

Gives the error:

error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
  --> src/lib.rs:22:26
   |
22 |         println!("{}", i.pow(2));
   |                          ^^^
help: you must specify a type for this binding, like `i32`
   |
21 |     for i: i32 in 0..1000 {
   |         ^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0689`

Implementing this recommendation by adding type to variable i as shown in the compiler recommendation and trying to compile again gives the error:

error: missing `in` in `for` loop
  --> src/lib.rs:21:10
   |
21 |     for i: i32 in 0..1000 {
   |          ^ help: try adding `in` here

error: expected expression, found `:`
  --> src/lib.rs:21:10
   |
21 |     for i: i32 in 0..1000 {
   |          ^ expected expression

error: aborting due to 2 previous errors

Not sure if there is a better solution, but adding a cast to the range rather than specifying the type of the variable worked for me:

pub fn check() {
    for i in 0..1000 as i32 {
        println!("{}", i.pow(2));
    }
}
A-diagnostics C-enhancement T-compiler

Most helpful comment

If https://github.com/rust-lang/rfcs/pull/2522 is accepted, the suggestion should work as is.

All 7 comments

If https://github.com/rust-lang/rfcs/pull/2522 is accepted, the suggestion should work as is.

Beside rfc2522, it's better to minimize the usages of as casts, so this is better:

for i in 0i32 .. 1000 {

Is there a reason to avoid as other than 0i32 being cleaner and more idiomatic? Those are good enough reasons. Just wondering if there are performance implications using as or other reasons to avoid it.

Given there is a good workaround and a forthcoming change, should this issue stay open or be closed? This is my first github issue and second week using Rust.

@spwitt: this issue can stay open! This is currently a valid issue with the diagnostics: it might just be worth waiting for the RFC (or making a temporary fix now).

Is there a reason to avoid as other than 0i32 being cleaner and more idiomatic?

In this example, no: all as i32 is doing is directing the type inference. 0i32 just looks slightly cleaner.

The incorrect suggestion is "fixed" in nightly since #51670:

error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
 --> src/lib.rs:3:26
  |
2 |     for i in 0..1000 {
  |         - you must specify a type for this binding, like `i32`
3 |         println!("{}", i.pow(2));
  |                          ^^^

Just wondering if there are performance implications using as or other reasons to avoid it.

Casting (as) has some tricky semantics. I particularly prefer using .into() when available (and that conversion is available only when as would always work as expected). When using as on literals it is fine for the most part, but then you already have the syntax proposed by @vankor which ends up looking cleaner. The only case where you'd need as (until TryFrom is available in stable) is when trying to downcast or cast to and from isize/usize.

@varkor I'm inclined to close this as duplicate of #51972 and #51634, but we probably should still improve the output to be

error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}`
 --> src/lib.rs:3:26
  |
2 |     for i in 0..1000 {
  |         -    - help: give this literal a type: `0i32`
  |         |
  |         you must specify a type for this binding, like `i32`
3 |         println!("{}", i.pow(2));
  |                          ^^^ can't call this method on ambiguous numeric type

cc @zackmdavis who proposed that in one of the linked tickets.

Is there a reason to avoid as other than 0i32 being cleaner and more idiomatic

The use of "as" should be minimized in Rust code because Rust doesn't perform overflow tests for "as" casts even in debug builds. It's a significant Rust design mistake.

Was this page helpful?
0 / 5 - 0 ratings