Skip to content

"try expression alternatives have incompatible types" is confusing wording #71309

Closed
@comex

Description

@comex

Simple example:

fn foo(x: Result<i32, ()>) -> Result<(), ()> {
    let y: u32 = x?;
    Ok(())
}

Compilation result (rust version 1.44.0-nightly (52fa23add 2020-04-18)):

error[E0308]: try expression alternatives have incompatible types
 --> src/lib.rs:2:18
  |
2 |     let y: u32 = x?;
  |                  ^^ expected `u32`, found `i32`
  |
help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
  |
2 |     let y: u32 = x?.try_into().unwrap();
  |                  ^^^^^^^^^^^^^^^^^^^^^^

Parts of this diagnostic are great, showing the mismatched types (u32 and i32) and even suggesting a valid possible fix. But the wording of the error itself is confusing. What "try expression alternatives"? I don't see any alternatives.

Taking a glance at the compiler implementation, it's referring to the arms of the match block that ? desugars into. But it's confusing to talk about those, because:

  • They're not visible to the user.

  • Why would there be a type mismatch between the arms in the first place, if there are only two arms and one of them always ends in a return rather than producing a value? Did type inference infer the error branch as having type u32 due to the context?

    If so, the message is technically accurate, but unhelpful: from the user's point of view, the 'real' issue is a mismatch between the expected type of x? (namely i32) and the context. As far as I can imagine, this is the only possible cause of a type mismatch between the arms of a desugared ?. So it seems like it would be fine to just change the error message to not mention the arms.

As a sidenote, if I take the -Zunpretty=hir output and try to compile that:

#![feature(try_trait)]
use std::ops::Try;
use std::convert::From;
fn foo(x: Result<i32, ()>) -> Result<(), ()> {
    let y: u32 = match Try::into_result(x) {
        Ok(val) => val,
        Err(err) => return Try::from_error(From::from(err)),
    };
    Ok(())
}

...oddly enough, I don't get a "match arms have incompatible types" error, but a more helpful one instead:

error[E0308]: mismatched types
 --> q.rs:6:20
  |
6 |         Ok(val) => val,
  |                    ^^^ expected `u32`, found `i32`
  |
help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit
  |
6 |         Ok(val) => val.try_into().unwrap(),
  |                    ^^^^

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsC-enhancementCategory: An issue proposing an enhancement or a PR with one.D-confusingDiagnostics: Confusing error or lint that should be reworked.D-incorrectDiagnostics: A diagnostic that is giving misleading or incorrect information.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.D-papercutDiagnostics: An error or lint that needs small tweaks.F-try_blocks`#![feature(try_blocks)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions