Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bad "Ambiguous Numeric Type" Recommendation from Compiler in for loop #53572

Open
spwitt opened this issue Aug 21, 2018 · 10 comments
Open

Bad "Ambiguous Numeric Type" Recommendation from Compiler in for loop #53572

spwitt opened this issue Aug 21, 2018 · 10 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@spwitt
Copy link

spwitt commented Aug 21, 2018

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));
    }
}
@varkor varkor added the A-diagnostics Area: Messages for errors, warnings, and lints label Aug 21, 2018
@varkor
Copy link
Member

varkor commented Aug 21, 2018

If rust-lang/rfcs#2522 is accepted, the suggestion should work as is.

@leonardo-m
Copy link

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

for i in 0i32 .. 1000 {

@spwitt
Copy link
Author

spwitt commented Aug 21, 2018

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.

@varkor
Copy link
Member

varkor commented Aug 22, 2018

@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.

@estebank
Copy link
Contributor

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.

@estebank
Copy link
Contributor

@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.

@leonardo-m
Copy link

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.

@estebank estebank added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 28, 2020
@crlf0710 crlf0710 added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jun 11, 2020
@DoumanAsh
Copy link

It is a bit off topic, but is it intended that compiler is unable to infer integer type from method usage?
For example 0.wrapping_shl(1u32);

@Z2Up1UwcaYOyZq
Copy link

Z2Up1UwcaYOyZq commented Apr 4, 2023

Issue is still valid

@estebank
Copy link
Contributor

Current output:

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));
  |                          ^^^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants