Change:
I have code that es on a , with cases for and . 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 () supports that this may be a bug. I tried this code (available at ): 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.
( 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 value, but the entire statement is not semicolon-terminated. If you replace the with, say, , you get a similar error: 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 or it needs to be semicolon-terminated. The error here could definitely be better. In your case, the error is about the match arms having different types because Rust apparently decides to unify the with the expected return value, instead of with the first match arm's value. If it resolved it with the then you'd see the error I listed above instead.
Given that, I'm removing I-wrong.
Huh, you're right. I always assumed that adding a semicolon to a statement-position shouldn't ever change anything.
Funnily enough, just the other day in IRC discovered the exact same thing :)
Another interesting test case, by from , that we should include as part of the fix:
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 . But it is a little different so I'm not really sure if should open a new issue: Play here: Using: rustc 1.14.0-nightly ( 2016-11-01)
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 case but ignore in the case?
So I think the fix here would involve basically throwing away individual match arms, returning instead of their type so as to "unify" when the match is in statement position. This seems relatively fine, but cc -- would we need an RFC for this? Is that the correct interpretation of the best option?
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: It seems clear to me that this function is supposed to return ; if you change the return type, it will compile. 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 that this is a purely diagnostic issue.
For case, the output is the original error: But if we "fix" the incompatible arms "problem", we get get a : I'm guessing that adding that suggestion to would be worthwhile (maybe with a suggestion to add a semicolon at the end of the match, but I don't think that's as worthwhile). code now produces a code suggestion to remove the incorrect semicolons:
Updated to Jan 2019: For case, the output is the original error: But if we "fix" the incompatible arms "problem", we get get a : I'm guessing that adding that suggestion to would be worthwhile (maybe with a suggestion to add a semicolon at the end of the match as we do in some cases, but I don't think that's as worthwhile). code now produces a code suggestion to remove the incorrect semicolons:
I believe there's little room for improvement here beyond what has been done so far:
I can't see why the examples you provided don't compile, while this chapter in the official book says that has a return type so should never conflict with other arms in a expression:
You're right, this error should suggest writing with a finishing semicolon. This arm is being evaluated to because that obligation is flowing up from the block.
Triage: this still produces the same diagnostics on the latest stable and nightly.
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 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
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 () errors with However, it compiles when I explicitly annotate the with a return type . Is it unreasonable to expect the compiler to deduce the type of function automatically to ?
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 That clarifies my question. Also, thanks for posting an explanation on the mentioned issue.
Maybe the diagnostic could attempt to perform that analysis on to see if , and either way we should be pointing at line 1 stating " returns ".
current output for the original report: There has been no movement in trying to probe a called function that returns to see if it could be instead. I'm not sure if we will.
I've made an interesting minimal contrasting pair that showcases this diagnostic issue: If you build the code: you get the error which is acceptable, and has useful tips that guide you in the right direction. However, if you wrap the in a { block }, like so: then you get the error: This error message has several issues. addition of the brackets has baffled those useful tips. feels like the compiler is lying to you about the type of , pointing directly at it and saying it "found ()" despite it having type . I realise that the compiler must have already coerced the type, but it feels kinda gaslight-y. compiler claims that the match arms have incompatible types, even though this isn't true. Rather, the compiler is coercing types across the boundary of the match statement before coercing between the different arms of the match statement, as you would intuitively expect would happen first. line doesn't appear anywhere in the error message, despite being the source of the inferred type, and it's being a candidate for the problem line.

Discussion:
&cause, Some(arm.body), arm_ty, <del> |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), </del> <ins> |err| { self.explain_never_type_coerced_to_unit(err, arm, arm_ty, prior_arm, expr); }, </ins> false, );

coercion.complete(self) } <ins> fn explain_never_type_coerced_to_unit( &self, err: &mut Diagnostic, arm: &hir::Arm<'tcx>, arm_ty: Ty<'tcx>, prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>, expr: &hir::Expr<'tcx>, ) { if let hir::ExprKind::Block(block, _) = arm.body.kind && let Some(expr) = block.expr && let arm_tail_ty = self.node_ty(expr.hir_id) && arm_tail_ty.is_never() && !arm_ty.is_never() { err.span_label( expr.span, format!( "this expression is of type `!`, but it is coerced to `{arm_ty}` due to its  surrounding expression", ), ); self.suggest_mismatched_types_on_tail( err, expr, arm_ty, prior_arm.map_or(arm_tail_ty, |(_, ty, _)| ty), expr.hir_id, ); } self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) } </ins> fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diagnostic,

// label pointing out the cause for the type coercion will be wrong // as prior return coercions would not be relevant (#57664). let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) { <ins> fcx.suggest_missing_semicolon(&mut err, expr, expected, false); </ins> let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); if let (Some(cond_expr), true, false) = (

coerce.coerce_forced_unit( self, &cause, <del> |err| { self.suggest_mismatched_types_on_tail(err, expr, ty, e_ty, target_id); </del> <ins> |mut err| { self.suggest_missing_semicolon(&mut err, expr, e_ty, false); self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); </ins> let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = ty_kind_suggestion(ty) {

blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); <del> self.suggest_missing_semicolon(err, expr, expected, false); </del> let mut pointing_at_return_type = false; if let hir::ExprKind::Break(..) = expr.kind { // `break` type mismatches provide better context for tail `loop` expressions.

<ins> fn never() -> ! { loop {} } fn bar(a: bool) { match a { true => 1, false => { never() //~ ERROR `match` arms have incompatible types } } } fn main() { bar(true); bar(false); } </ins>

<ins> 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 is coerced to `()` due to its surrounding expression LL | |         } LL | |     } | |_____- `match` arms have incompatible types error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. </ins>