Skip to content

Commit bb341ca

Browse files
committed
Improve error message for assert!() macro in functions returning bool
When assert!() is used in a function that returns a value, the compiler emits a confusing error message suggesting the if expression is missing an else clause. This commit detects when the if expression comes from an assert!() or debug_assert!() macro expansion and provides a clearer error message explaining that assert!() does not return a value.
1 parent 625b63f commit bb341ca

File tree

3 files changed

+103
-3
lines changed

3 files changed

+103
-3
lines changed

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
44
use rustc_hir::{self as hir, ExprKind, HirId, PatKind};
55
use rustc_hir_pretty::ty_to_string;
66
use rustc_middle::ty::{self, Ty};
7-
use rustc_span::Span;
7+
use rustc_span::{Span, sym};
88
use rustc_trait_selection::traits::{
99
MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
1010
};
@@ -291,6 +291,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
291291
error
292292
}
293293

294+
/// Check if the span comes from an assert-like macro expansion.
295+
fn is_from_assert_macro(&self, span: Span) -> bool {
296+
span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
297+
if let Some(name) = self.tcx.get_diagnostic_name(def_id) {
298+
matches!(
299+
name,
300+
sym::assert_macro
301+
| sym::debug_assert_macro
302+
| sym::assert_eq_macro
303+
| sym::assert_ne_macro
304+
| sym::debug_assert_eq_macro
305+
| sym::debug_assert_ne_macro
306+
)
307+
} else {
308+
false
309+
}
310+
})
311+
}
312+
294313
/// Explain why `if` expressions without `else` evaluate to `()` and detect likely irrefutable
295314
/// `if let PAT = EXPR {}` expressions that could be turned into `let PAT = EXPR;`.
296315
fn explain_if_expr(
@@ -302,15 +321,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
302321
then_expr: &'tcx hir::Expr<'tcx>,
303322
error: &mut bool,
304323
) {
324+
let is_assert_macro = self.is_from_assert_macro(if_span);
325+
305326
if let Some((if_span, msg)) = ret_reason {
306327
err.span_label(if_span, msg);
307328
} else if let ExprKind::Block(block, _) = then_expr.kind
308329
&& let Some(expr) = block.expr
309330
{
310331
err.span_label(expr.span, "found here");
311332
}
312-
err.note("`if` expressions without `else` evaluate to `()`");
313-
err.help("consider adding an `else` block that evaluates to the expected type");
333+
334+
if is_assert_macro {
335+
err.primary_message("mismatched types");
336+
} else {
337+
err.note("`if` expressions without `else` evaluate to `()`");
338+
err.help("consider adding an `else` block that evaluates to the expected type");
339+
}
314340
*error = true;
315341
if let ExprKind::Let(hir::LetExpr { span, pat, init, .. }) = cond_expr.kind
316342
&& let ExprKind::Block(block, _) = then_expr.kind
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//@ dont-require-annotations: NOTE
2+
3+
fn f() -> bool {
4+
assert!(1 < 2)
5+
//~^ ERROR mismatched types [E0317]
6+
}
7+
8+
fn g() -> i32 {
9+
assert_eq!(1, 1)
10+
//~^ ERROR mismatched types [E0317]
11+
}
12+
13+
fn h() -> bool {
14+
assert_ne!(1, 2)
15+
//~^ ERROR mismatched types [E0317]
16+
}
17+
18+
// Test nested macros
19+
macro_rules! g {
20+
() => {
21+
f!()
22+
};
23+
}
24+
macro_rules! f {
25+
() => {
26+
assert!(1 < 2)
27+
//~^ ERROR mismatched types [E0317]
28+
};
29+
}
30+
fn nested() -> bool {
31+
g!()
32+
}
33+
34+
fn main() {}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error[E0317]: mismatched types
2+
--> $DIR/assert-macro-without-else.rs:4:5
3+
|
4+
LL | fn f() -> bool {
5+
| ---- expected `bool` because of this return type
6+
LL | assert!(1 < 2)
7+
| ^^^^^^^^^^^^^^ expected `bool`, found `()`
8+
9+
error[E0317]: mismatched types
10+
--> $DIR/assert-macro-without-else.rs:9:5
11+
|
12+
LL | assert_eq!(1, 1)
13+
| ^^^^^^^^^^^^^^^^ expected `i32`, found `()`
14+
|
15+
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
16+
17+
error[E0317]: mismatched types
18+
--> $DIR/assert-macro-without-else.rs:14:5
19+
|
20+
LL | assert_ne!(1, 2)
21+
| ^^^^^^^^^^^^^^^^ expected `bool`, found `()`
22+
|
23+
= note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
24+
25+
error[E0317]: mismatched types
26+
--> $DIR/assert-macro-without-else.rs:26:9
27+
|
28+
LL | assert!(1 < 2)
29+
| ^^^^^^^^^^^^^^ expected `bool`, found `()`
30+
...
31+
LL | fn nested() -> bool {
32+
| ---- expected `bool` because of this return type
33+
LL | g!()
34+
| ---- in this macro invocation
35+
|
36+
= note: this error originates in the macro `assert` which comes from the expansion of the macro `g` (in Nightly builds, run with -Z macro-backtrace for more info)
37+
38+
error: aborting due to 4 previous errors
39+
40+
For more information about this error, try `rustc --explain E0317`.

0 commit comments

Comments
 (0)