From 7db8300932219eecabf25c4df0fdadc2b4628c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Dec 2025 19:52:23 +0000 Subject: [PATCH] Detail expectation on non-`()` block tail in `if` then condition with no `else` When encountering an `if` expression with no `else` where the then block has a tail expression, we emit an E0308 type error. We now explain why `()` was expected. --- compiler/rustc_hir_typeck/src/coercion.rs | 15 ++++++++++++++- ...e-for-type-mismatch-in-closure-in-async.stderr | 2 +- .../missing-return-in-async-block.stderr | 4 ++-- .../unused/unused-doc-comments-edge-cases.stderr | 2 +- .../ui/loops/dont-suggest-break-thru-item.stderr | 8 ++++---- .../struct-literals-in-invalid-places.stderr | 2 +- .../issue-82612-return-mutable-reference.stderr | 2 +- .../return/tail-expr-as-potential-return.stderr | 6 +++--- tests/ui/return/tail-expr-if-as-return.stderr | 2 +- .../try-operator-dont-suggest-semicolon.rs | 2 +- .../try-operator-dont-suggest-semicolon.stderr | 2 +- 11 files changed, 30 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 127965cb4b301..4ee3a0cb76efd 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1880,7 +1880,20 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) ) { - err.span_label(cond_expr.span, "expected this to be `()`"); + if let ObligationCauseCode::BlockTailExpression(hir_id, hir::MatchSource::Normal) = + cause.code() + && let hir::Node::Block(block) = fcx.tcx.hir_node(*hir_id) + && let hir::Node::Expr(expr) = fcx.tcx.parent_hir_node(block.hir_id) + && let hir::Node::Expr(if_expr) = fcx.tcx.parent_hir_node(expr.hir_id) + && let hir::ExprKind::If(_cond, _then, None) = if_expr.kind + { + err.span_label( + cond_expr.span, + "expected this `if` expression to be `()` because it has no `else` arm", + ); + } else { + err.span_label(cond_expr.span, "expected this to be `()`"); + } if expr.can_have_side_effects() { fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); } diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr index ce023397db90a..2fce0f2e05b5d 100644 --- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -6,7 +6,7 @@ LL | | false | | ^^^^^ expected `()`, found `bool` LL | | LL | | } - | |_________- expected this to be `()` + | |_________- expected this `if` expression to be `()` because it has no `else` arm error[E0308]: mismatched types --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9 diff --git a/tests/ui/async-await/missing-return-in-async-block.stderr b/tests/ui/async-await/missing-return-in-async-block.stderr index 5ea76e5f7bf93..43d022e8d2273 100644 --- a/tests/ui/async-await/missing-return-in-async-block.stderr +++ b/tests/ui/async-await/missing-return-in-async-block.stderr @@ -5,7 +5,7 @@ LL | / if true { LL | | Ok(S) | | ^^^^^ expected `()`, found `Result` LL | | } - | |_________- expected this to be `()` + | |_________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result` @@ -21,7 +21,7 @@ LL | / if true { LL | | Ok(S) | | ^^^^^ expected `()`, found `Result` LL | | } - | |_________- expected this to be `()` + | |_________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result` diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index c074117455493..4e138f35fa3ae 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -105,7 +105,7 @@ LL | / if num == 3 { LL | | true | | ^^^^ expected `()`, found `bool` LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm | help: you might have meant to return this value | diff --git a/tests/ui/loops/dont-suggest-break-thru-item.stderr b/tests/ui/loops/dont-suggest-break-thru-item.stderr index e7ed7ae15015e..5f326b6b0652a 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.stderr +++ b/tests/ui/loops/dont-suggest-break-thru-item.stderr @@ -6,7 +6,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____________- expected this to be `()` + | |_____________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -23,7 +23,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____________- expected this to be `()` + | |_____________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -40,7 +40,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` LL | | LL | | } - | |_____________- expected this to be `()` + | |_____________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -53,7 +53,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` LL | | LL | | } - | |_____________- expected this to be `()` + | |_____________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr index 39dc2d2efb75b..a854c6900421b 100644 --- a/tests/ui/parser/struct-literals-in-invalid-places.stderr +++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr @@ -200,7 +200,7 @@ LL | if x == E::V { field } {} | ---------------^^^^^-- | | | | | expected `()`, found `bool` - | expected this to be `()` + | expected this `if` expression to be `()` because it has no `else` arm | help: you might have meant to return this value | diff --git a/tests/ui/return/issue-82612-return-mutable-reference.stderr b/tests/ui/return/issue-82612-return-mutable-reference.stderr index 59a6bb85d0fd3..e7bd31c3695e0 100644 --- a/tests/ui/return/issue-82612-return-mutable-reference.stderr +++ b/tests/ui/return/issue-82612-return-mutable-reference.stderr @@ -6,7 +6,7 @@ LL | | let value = unsafe { self.values.get_unchecked_mut(index) }; LL | | value.get_or_insert_with(func) | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&mut V` LL | | } - | |_________- expected this to be `()` + | |_________- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found mutable reference `&mut V` diff --git a/tests/ui/return/tail-expr-as-potential-return.stderr b/tests/ui/return/tail-expr-as-potential-return.stderr index 8105b2df3fea6..236eab1eca9df 100644 --- a/tests/ui/return/tail-expr-as-potential-return.stderr +++ b/tests/ui/return/tail-expr-as-potential-return.stderr @@ -6,7 +6,7 @@ LL | | Err(42) | | ^^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -23,7 +23,7 @@ LL | | 1i32 | | ^^^^ expected `()`, found `i32` ... | LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm | help: you might have meant to return this value | @@ -38,7 +38,7 @@ LL | | Err(42) | | ^^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm | = note: expected unit type `()` found enum `Result<_, {integer}>` diff --git a/tests/ui/return/tail-expr-if-as-return.stderr b/tests/ui/return/tail-expr-if-as-return.stderr index 2631f1e426ded..ef70a1caad746 100644 --- a/tests/ui/return/tail-expr-if-as-return.stderr +++ b/tests/ui/return/tail-expr-if-as-return.stderr @@ -5,7 +5,7 @@ LL | / if true { LL | | "" | | ^^ expected `()`, found `&str` LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs index f882a159f9834..4fff3d7a8b063 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), ()> { // Here, we do want to suggest a semicolon: let x = Ok(42); if true { - //~^ NOTE: expected this to be `()` + //~^ NOTE: expected this `if` expression to be `()` because it has no `else` arm x? //~^ ERROR: mismatched types [E0308] //~| NOTE: expected `()`, found integer diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr index a275f0c2fa898..8204292d96a73 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr @@ -15,7 +15,7 @@ LL | | x? | | ^^ expected `()`, found integer ... | LL | | } - | |_____- expected this to be `()` + | |_____- expected this `if` expression to be `()` because it has no `else` arm | help: consider using a semicolon here |