-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Incorrect "match arms have incompatible types" error message #24157
Comments
(@steveklabnik I don't think the A-diagnostics label is appropriate for this issue. The bug is that this gives an error at all, not that the error message is bad, so perhaps I-wrong would be better?) |
I mean, it's a very bad error regardless, but yeah, maybe. I'll add it too. |
My rustc version, if it helps
|
Yielding an error is correct here. The error message is merely misleading. The core issue here is your first match arm is attempting to evaluate to a
This is also a bit misleading. The error looks like this because the match expression occurs in statement position, so either the match expression needs to resolve to the type |
Given that, I'm removing I-wrong. |
@kballard Huh, you're right. I always assumed that adding a semicolon to a statement-position |
Funnily enough, just the other day in IRC @bstrie discovered the exact same thing :) |
Another interesting test case, by @Binero from #24568, that we should include as part of the fix: fn main() {
is_one(1)
}
fn is_one(a: u8) {
match a {
1 => true,
_ => panic!("It's not one!"),
}
}
|
Just to note, that this is super confusing for new rust developers - I sought help in #rust after beating my head on the wall for a bit :) |
Another code that to me looks the same issue or even #35685. But it is a little different so I'm not really sure if should open a new issue:
Play here: https://is.gd/GTv1gf |
Could someone outline what the recommended approach is for differently typed match arms? What do I do with options where i want to just run a operation in the |
So I think the fix here would involve basically throwing away individual match arms, returning |
The current behavior seems preferable to a change to me. In all of these cases you are doing something quite unidiomatic, and in several the programmer has almost certainly made a mistake and should receive an error. For example: fn is_one(a: u8) {
match a {
1 => true,
_ => panic!("It's not one!"),
}
} It seems clear to me that this function is supposed to return For the rest of them I see similar errors. There are diagnostics issues, but I definitely think nothing should change about the semantics. |
I agree with @withoutboats that this is a purely diagnostic issue. |
This comment has been minimized.
This comment has been minimized.
Updated to Jan 2019: For @withoutboats case, the output is the original error:
But if we "fix" the incompatible arms "problem", we get get a suggestion to change the return type:
I'm guessing that adding that suggestion to @fungos's code now produces a code suggestion to remove the incorrect semicolons:
|
Tweak "incompatible match arms" error - Point at the body expression of the match arm with the type error. - Point at the prior match arms explicitly stating the evaluated type. - Point at the entire match expr in a secondary span, instead of primary. - For type errors in the first match arm, the cause is outside of the match, treat as implicit block error to give a more appropriate error. Fix rust-lang#46776, fix rust-lang#57206. CC rust-lang#24157, rust-lang#38234.
Tweak "incompatible match arms" error - Point at the body expression of the match arm with the type error. - Point at the prior match arms explicitly stating the evaluated type. - Point at the entire match expr in a secondary span, instead of primary. - For type errors in the first match arm, the cause is outside of the match, treat as implicit block error to give a more appropriate error. Fix rust-lang#46776, fix rust-lang#57206. CC rust-lang#24157, rust-lang#38234.
I believe there's little room for improvement here beyond what has been done so far:
|
…oli-obk Detect match statement intended to be tail expression CC rust-lang#24157
…i-obk Detect match statement intended to be tail expression CC rust-lang#24157
Triage report: emits the correct diagnostic for Rust Edition 2021, and thus we could close this, but before we do so, I should note that I added the caveat there quite deliberately as this actually emits the wrong diagnostic still, in a very weird way, on Edition 2015 and Edition 2018:
stable/nightly doesn't seem to matter. rustc version is 1.61.0 |
@workingjubilee, I agree that the ticket should remain open, although with a lower priority :) Thanks for triaging! |
Sorry for bumping on the existing issue. But the problem I encounter is very relevant to this issue. The snippet (playground) fn exit_wrapper() {
std::process::exit(1)
}
fn main() {
let mut input: String = String::new();
match std::io::stdin().read_line(&mut input) {
Ok(u) => u,
Err(_e) => exit_wrapper(),
};
} errors with
However, it compiles when I explicitly annotate the |
Basically: yes. You are asking for the deduction Rust decided to not attempt. Function signatures are a coercion site and must remain stable despite their interior for various other stability promises to mean much, so the function signature must dominate over whatever the contents are. This is relaxed in very specific cases, but those cases are ones where a type can be inferred along the "exterior" of the function signature, and the "interior" will not have any meaningful effect on the type deduced. |
Thank you @workingjubilee. That clarifies my question. Also, thanks for posting an explanation on the mentioned issue. |
Maybe the diagnostic could attempt to perform that analysis on |
current output for the original report:
There has been no movement in trying to probe a called function that returns |
I've made an interesting minimal contrasting pair that showcases this diagnostic issue: Playground If you build the code: fn never() -> ! {
loop {}
}
fn foo(a: bool) {
match a {
true => 1,
false => never(),
}
} you get the error
which is acceptable, and has useful fn bar(a: bool) {
match a {
true => 1,
false => {
never()
}
}
} then you get the error:
This error message has several issues.
|
On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
Account for `!` arm in tail `match` expr On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
Account for `!` arm in tail `match` expr On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
Account for `!` arm in tail `match` expr On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
Account for `!` arm in tail `match` expr On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
Rollup merge of rust-lang#117526 - estebank:issue-24157, r=b-naber Account for `!` arm in tail `match` expr On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
On functions with a default return type that influences the coerced type of `match` arms, check if the failing arm is actually of type `!`. If so, suggest changing the return type so the coercion against the prior arms is successful. ``` error[E0308]: `match` arms have incompatible types --> $DIR/match-tail-expr-never-type-error.rs:9:13 | LL | fn bar(a: bool) { | - help: try adding a return type: `-> i32` LL | / match a { LL | | true => 1, | | - this is found to be of type `{integer}` LL | | false => { LL | | never() | | ^^^^^^^ | | | | | expected integer, found `()` | | this expression is of type `!`, but it get's coerced to `()` due to its surrounding expression LL | | } LL | | } | |_____- `match` arms have incompatible types ``` Fix rust-lang#24157.
I have code that
match
es on aResult<usize>
, with cases forOk(usize_var)
andErr(why)
. I get a "match arms have incompatible types" error upon compilation which I believe is incorrect.I'm not incredibly experienced with this, but discussion in irc (https://botbot.me/mozilla/rust/2015-04-06/?msg=35985521&page=37) supports that this may be a bug.
I tried this code (available at http://is.gd/Y00aRi):
I expected it to compile, however there is a "match arms have incompatible types" error even though I believe the match arms should both be of type usize.
I should note that adding a semicolon after the match causes clean compilation.
The text was updated successfully, but these errors were encountered: