rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.78k stars 12.65k forks source link

Numeric fallbacks don't work when inherent methods are involved #24124

Open XMPPwocky opened 9 years ago

XMPPwocky commented 9 years ago

I would expect 2.0.sqrt() to return sqrt(2) as a f64. Instead,

<anon>:9:13: 9:19 error: type `_` does not implement any method in scope named `sqrt`
<anon>:9         2.0.sqrt()

<anon>:9:19: 9:19 help: methods from traits can only be called if the trait is in scope; the following traits are implemented but not in scope, perhaps add a `use` for one of them:
<anon>:9:19: 9:19 help: candidate #1: use `std::num::Float`
<anon>:9:19: 9:19 help: candidate #2: use `core::num::Float`

... and the Float trait is deprecated!

This also occurs with integer literals.

I ran into this in the wild while doing an exponential decay:

let k = c * 2.0.powf(-1.0 * scale * dt);

A workaround is to annotate the literal's type explicitly.

azar77 commented 9 years ago

I encountered a similar problem:

fn sqrt2() -> f64 {
    let x = 2.0;
    x.sqrt()
}

fn two_plus_three() -> u64 {
    let x = 2;
    x.checked_add(3).unwrap()
}

In both cases, the compiler fails to infer the type of x even though it has enough information to do so (from the return value of the functions).

IvanUkhov commented 8 years ago

Moreover, the language reference says that

If the program context under-constrains the type, it defaults to f64.

So, if the reference was respected, it would default to f64 and call the right method.

CasualX commented 7 years ago

I just ran into this writing some example codes (where it's more likely to have a lot of 'unconstrained' hard coded constants), note the very unhelpful error message:

fn main() {
    let _ = 0.5.sqrt();
}
error: no method named `sqrt` found for type `{float}` in the current scope
 --> src/main.rs:2:21
  |
2 |         let _ = 0.5.sqrt();
  |                     ^^^^
  |
  = help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
  = help: candidate #1: `use rand::FloatMath;`

error: aborting due to previous error

error: Could not compile `playground`.

To learn more, run the command again with --verbose.

https://play.rust-lang.org/?gist=24e7667d5a1ea0c7b8702e9ac4a075b4&version=stable

zackw commented 7 years ago

This was also reported as a pain point in the "Ideas for making Rust easier for beginners" internals thread: https://internals.rust-lang.org/t/ideas-for-making-rust-easier-for-beginners/4761/37

jimblandy commented 5 years ago

Readers of our book 'Programming Rust' have reported errata related to this, because it's hard to explain that operators and trait methods work on unresolved {float} values, but associated functions don't.

estebank commented 1 year ago

The current error is much clearer, but this ticket is still valid because it is about inference itself:

error[E0689]: can't call method `sqrt` on ambiguous numeric type `{float}`
 --> src/main.rs:2:17
  |
2 |     let _ = 0.5.sqrt();
  |                 ^^^^
  |
help: you must specify a concrete type for this numeric value, like `f32`
  |
2 |     let _ = 0.5_f32.sqrt();
  |             ~~~~~~~
madsmtm commented 10 months ago

Weirdly enough, this does work for trait methods (playground):

trait Foo {
    fn foo(&self);
}

impl Foo for i16 {
    fn foo(&self) {
        println!("i16");
    }
}

// Uncomment to change the output in `main`
//
// impl Foo for i32 {
//     fn foo(&self) {
//         println!("i32");
//     }
// }

fn main() {
    3.foo();
}

So it definitely seems like it should be possible.