A confusing inferred type for `parse`

struct A;
impl A{
    fn new()->Result<Self,std::num::ParseIntError>{
        let c = "1".parse()?;
        Ok(A)
    }
}
fn main() {

}

Given this code, the compiler complains that

the trait bound (): FromStr is not satisfied

However, why is the generic type F in parse inferred to be type ()? This is confusion, the expected error would be

type annotations needed

If we desugar the above code to

struct A;
impl A{
    fn new()->Result<Self,std::num::ParseIntError>{
        let c = match "1".parse(){
            Ok(v)=>{v}
            Err(e)=>{
                return Err(e.into());
            }
        };
        Ok(A)
    }
}
fn main() {

}

The expected diagnosis will be given.

The () type has exactly one value () , and is used when there is no other meaningful value that could be returned.

So let c /*: () */ = "1".parse()?; by default. And the trait bound is indeed not met.

On mobile, but that's not the (notional) desugaring (look up the Try trait).

That's just what happens. It's not optimal, but it's actually better then the "type annotations needed".

The problem is that if you want let _r = Err(123_u32); to work, it needs to pick something for the E type.

() might not be the best option, but it's what we have for now.

The () type has exactly one value () , and is used when there is no other meaningful value that could be returned.

If the type () were alternatively used in any context that cannot determine the type, then "need annotation type" wouldn't be given in any cases.

To clarify what you have now:

  • the first snippet generates error[E0277]: the trait bound (): FromStr is not satisfied
  • the second snippet generates error[E0282]: type annotations needed

And your current question is why type annotation is needed in the first case, which is an incorrect question since that's not the error.

As mentioned by others, the second snippet is wrong desugaring in ?. And it says type annotation for Result::Err is needed, not for parse method.

So, what is the rule of type inference? If it is any generic type that cannot be inferred will be (), how do you interpret this example?

fn show<F:Default>()->F{
    F::default()
}
fn main() {
   let c = show();
}

I don't know why we chose the type () as the inferred type for the generic type in this context. If any generic type that cannot be inferred is determined to (), why this example is not?

fn show<F:Default>()->F{
    F::default()
}
fn main() {
   let c = show();  // type annotation needed, why it is not inferred to just `()`
}

show function is not in the same form as parse in OP. A reproduce is

use anyhow::Result;
fn show<F: Default>() -> Result<F> {
    Ok(F::default())
}
fn main() -> Result<()> {
    let c = show()?; // This compiles since `(): Default`
    Ok(())
}

A nitpick: if you omit ?, the error a little varies

// fn show<F: Default>() -> Result<F> 
error[E0283]: type annotations needed
 --> src/main.rs:7:13
  |
7 |     let c = show();
  |             ^^^^ cannot infer type of the type parameter `F` declared on the function `show`
  |
  = note: cannot satisfy `_: Default`
note: required by a bound in `show`
 --> src/main.rs:3:12
  |
3 | fn show<F: Default>() -> Result<F> {
  |            ^^^^^^^ required by this bound in `show`
help: consider specifying the generic argument
  |
7 |     let c = show::<F>();
  |                 +++++

but yours:

// fn show<F:Default>()->F
error[E0282]: type annotations needed
 --> src/main.rs:5:8
  |
5 |    let c = show();
  |        ^
  |
help: consider giving `c` an explicit type
  |
5 |    let c: /* Type */ = show();
  |         ++++++++++++

So, why do show() and show()? have different result? In other words, the type inferred for show in show()? is () while the type annotation is needed in show()?

I don't know :slight_smile:

Type inference - Rust Compiler Development Guide is the starting point for these questions I think.

In Rust, type inference follows certain rules:

In variable declarations or function parameters, the type of the variable is inferred from the initialized value.

The return type of a function can be inferred based on its implementation.

Types defined using the type keyword are replaced with their actual type at compile time.

Types defined within a struct are inferred to be of that specific type.

When using smart pointers like &, *, Box, Vec, String, etc., Rust infers the type of the pointer and what it points to.

When calling a method, Rust infers the return type based on the method's definition and the receiver's type.

Same fallback to (). More reading I don't have time to do:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.