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

Compiler unable to infer obvious types #120256

Closed
tryoxiss opened this issue Jan 23, 2024 · 5 comments
Closed

Compiler unable to infer obvious types #120256

tryoxiss opened this issue Jan 23, 2024 · 5 comments
Labels
A-inference Area: Type inference C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@tryoxiss
Copy link

tryoxiss commented Jan 23, 2024

I tried this code:

#[derive(PartialEq)]
struct Vector2<N = f32>
{
    x: N,
    y: N,
}

impl<N> Vector2<N>
{
    pub fn new(x: f32, y: f32) -> Vector2::<f32>
    {
        return Vector2::<f32> { x: x as f32, y: y as f32 };
    }
    
    // note for this you will need to specify the exact type, such as 
    // 1.0 as i16 since rust will use i32 -> f64 in that order, when possible.
    pub fn new_as<T>(x: T, y: T) -> Vector2::<T>
    {
        return Vector2::<T> { x: x as T, y: y as T }
    }
}

fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

fn main()
{
    //let a = Vector2::<f32> { x: 1.0, y: 1.0 };
    //let b = Vector2::<f64> { x: 1.0, y: 1.0 };
    //let c = Vector2 { x: 1.0, y: 1 };
    
    let c: Vector2::<f32> = Vector2::new(1.0, 2.0);
    let d: Vector2::<i8> = Vector2::<i8>::new_as(1, 1);
    
    //print_type_of(&a);
    //print_type_of(&b);
    // print_type_of(&c);
    print_type_of(&d);
    
    //println!("{}", a == b);
}

I tried much less type annotated versions getting increasingly annoyed, until I tried that, which of course still didn't work. I know the simple fix is to add ::<f32> -- the compiler can tell be that. But with all the type annotations I feel like it should be able to figure out that thats just what I want. I mean, if I specify let x = 1.0 I don't need to tell it its an f64!

Normally I love type hinting, but with the amount vectors are used in gamedev--with almost all of them being f32--it feels awkward and bad UX to need to specify every time. I don't quite know if this is a bug, but I feel like it falls into that category. Especially since its returning a Vector2 with two paramaters which are explictly f32

Instead, this happened: Compiler error:

   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed
  --> src/main.rs:33:29
   |
33 |     let c: Vector2::<f32> = Vector2::new(1.0, 2.0);
   |                             ^^^^^^^^^^^^ cannot infer type of the type parameter `N` declared on the struct `Vector2`
   |
help: consider specifying the generic argument
   |
33 |     let c: Vector2::<f32> = Vector2::<N>::new(1.0, 2.0);
   |                                    +++++

For more information about this error, try `rustc --explain E0282`.
error: could not compile `playground` (bin "playground") due to previous error

Meta

rustc --version --verbose:

rustc 1.73.0-nightly (f3623871c 2023-08-06)
binary: rustc
commit-hash: f3623871cfa0763c95ebd6ceafaa6dc2e44ca68f
commit-date: 2023-08-06
host: x86_64-unknown-linux-gnu
release: 1.73.0-nightly
LLVM version: 16.0.5

(also tried on stable, identical issue)

And yes this was with rust backtrace, I don't know why its the same. ![image](https://github.com/rust-lang/rust/assets/94419893/4b7cb6d0-fc27-4020-9e3f-c349b8243cf6)

   Compiling vec_test v0.1.0 (/home/madeline/tmp/vec_test)
error[E0282]: type annotations needed
  --> src/main.rs:33:29
   |
33 |     let c: Vector2::<f32> = Vector2::new(1.0, 2.0);
   |                             ^^^^^^^^^^^^ cannot infer type of the type parameter `N` declared on the struct `Vector2`
   |
help: consider specifying the generic argument
   |
33 |     let c: Vector2::<f32> = Vector2::<N>::new(1.0, 2.0);
   |                                    +++++

For more information about this error, try `rustc --explain E0282`.
error: could not compile `vec_test` (bin "vec_test") due to previous error

@tryoxiss tryoxiss added the C-bug Category: This is a bug. label Jan 23, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Jan 23, 2024
@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-inference Area: Type inference C-discussion Category: Discussion or questions that doesn't represent real issues. and removed C-bug Category: This is a bug. needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Jan 23, 2024
@fmease
Copy link
Member

fmease commented Jan 23, 2024

Reproducer minimized from the issue description to better describe what's going on:

struct Vector2<N = f32>
{
    x: N,
    y: N,
}

impl<N> Vector2<N>
{
    pub fn new(x: f32, y: f32) -> Vector2<f32>
    {
        Vector2 { x, y }
    }
}

fn main()
{
    let _: Vector2<f32> = Vector2::new(1.0, 2.0); //~ ERROR type annotations needed
    //~^ cannot infer type of the type parameter `N` declared on the struct `Vector2`
    //~| HELP consider specifying the generic argument
}

@fmease
Copy link
Member

fmease commented Jan 23, 2024

It's a known limitation that type parameter defaults (here: N = f32 on Vector2) don't participate in type inference (they're not considered as fallbacks). CC #27336, #83687, #96300, #98931, #114736.

@fmease
Copy link
Member

fmease commented Jan 23, 2024

In this case, you can easily fix this by changing the impl header from <N> Vector2<N> to Vector2 / Vector<f32>:

impl Vector2
{
    pub fn new(x: f32, y: f32) -> Vector2<f32>
    {
        Vector2 { x, y }
    }
}

Which can be further simplified to:

impl Vector2
{
    pub fn new(x: f32, y: f32) -> Self
    {
        Self { x, y }
    }
}

@fmease
Copy link
Member

fmease commented Jan 23, 2024

Closing as a duplicate of #98931.

@fmease fmease closed this as not planned Won't fix, can't repro, duplicate, stale Jan 23, 2024
@tryoxiss
Copy link
Author

tryoxiss commented Jan 23, 2024

In this case, you can easily fix this by changing the impl header from <N> Vector2<N> to Vector2 / Vector<f32>:

impl Vector2
{
    pub fn new(x: f32, y: f32) -> Vector2<f32>
    {
        Vector2 { x, y }
    }
}

Which can be further simplified to:

impl Vector2
{
    pub fn new(x: f32, y: f32) -> Self
    {
        Self { x, y }
    }
}

Thank you, this is exactly what I wanted! I feel like this could be a compiler suggestion though! /pos


For anyone in the future I ended up with this to have both generic capacity and f32 defaults:

// --snip--

impl Vector2
{
    pub fn new(x: f32, y: f32) -> Vector2::<f32>
    {
        return Vector2 { x: x, y: y };
    }
}

impl<N> Vector2<N>
{
    // note for this you will need to specify the exact type, such as 
    // 1.0 as i16 since rust will use i32 -> f64 in that order, when possible.
    pub fn new_as<T>(x: T, y: T) -> Vector2::<T>
    {
        return Vector2::<T> { x: x as T, y: y as T }
    }
}

// --snip--

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference C-discussion Category: Discussion or questions that doesn't represent real issues. 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

3 participants