diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index fb03b93b249..b1074745d72 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -16,6 +16,11 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}` *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it } +hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` + .suggestion = compare with zero instead + .help = compare with zero instead + .label = unsupported cast + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 9835951f948..bb1b7f2534f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -322,33 +322,13 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToBool => { - let mut err = struct_span_err!( - fcx.tcx.sess, - self.span, - E0054, - "cannot cast `{}` as `bool`", - self.expr_ty - ); - - if self.expr_ty.is_numeric() { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { - Ok(snippet) => { - err.span_suggestion( - self.span, - "compare with zero instead", - format!("{snippet} != 0"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - err.span_help(self.span, "compare with zero instead"); - } - } + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let help = if self.expr_ty.is_numeric() { + errors::CannotCastToBoolHelp::Numeric(self.expr_span.shrink_to_hi().with_hi(self.span.hi())) } else { - err.span_label(self.span, "unsupported cast"); - } - - err.emit(); + errors::CannotCastToBoolHelp::Unsupported(self.span) + }; + fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help }); } CastError::CastToChar => { let mut err = type_error_struct!( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 11b555ba095..3bfe5a22df6 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -541,6 +541,29 @@ pub struct CandidateTraitNote { pub action_or_ty: String, } +#[derive(Diagnostic)] +#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")] +pub struct CannotCastToBool<'tcx> { + #[primary_span] + pub span: Span, + pub expr_ty: Ty<'tcx>, + #[subdiagnostic] + pub help: CannotCastToBoolHelp, +} + +#[derive(Subdiagnostic)] +pub enum CannotCastToBoolHelp { + #[suggestion( + hir_typeck_suggestion, + applicability = "machine-applicable", + code = " != 0", + style = "verbose" + )] + Numeric(#[primary_span] Span), + #[label(hir_typeck_label)] + Unsupported(#[primary_span] Span), +} + #[derive(Diagnostic)] #[diag(hir_typeck_ctor_is_private, code = "E0603")] pub struct CtorIsPrivate { diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs index 750a88f97eb..511a02718fe 100644 --- a/tests/ui/cast/cast-as-bool.rs +++ b/tests/ui/cast/cast-as-bool.rs @@ -1,11 +1,11 @@ fn main() { let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead - //~| SUGGESTION 5 != 0 + //~| SUGGESTION != 0 let t = (1 + 2) as bool; //~ ERROR cannot cast `i32` as `bool` //~| HELP compare with zero instead - //~| SUGGESTION (1 + 2) != 0 + //~| SUGGESTION != 0 let _ = 5_u32 as bool; //~ ERROR cannot cast `u32` as `bool` //~| HELP compare with zero instead diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr index 852fb30cc20..4ff56a95e49 100644 --- a/tests/ui/cast/cast-as-bool.stderr +++ b/tests/ui/cast/cast-as-bool.stderr @@ -2,25 +2,45 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-as-bool.rs:2:13 | LL | let u = 5 as bool; - | ^^^^^^^^^ help: compare with zero instead: `5 != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let u = 5 != 0; + | ~~~~ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-as-bool.rs:6:13 | LL | let t = (1 + 2) as bool; - | ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0` + | ^^^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let t = (1 + 2) != 0; + | ~~~~ error[E0054]: cannot cast `u32` as `bool` --> $DIR/cast-as-bool.rs:10:13 | LL | let _ = 5_u32 as bool; - | ^^^^^^^^^^^^^ help: compare with zero instead: `5_u32 != 0` + | ^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 5_u32 != 0; + | ~~~~ error[E0054]: cannot cast `f64` as `bool` --> $DIR/cast-as-bool.rs:13:13 | LL | let _ = 64.0_f64 as bool; - | ^^^^^^^^^^^^^^^^ help: compare with zero instead: `64.0_f64 != 0` + | ^^^^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 64.0_f64 != 0; + | ~~~~ error[E0054]: cannot cast `IntEnum` as `bool` --> $DIR/cast-as-bool.rs:24:13 diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr index 5dc21ca847c..dd90c3a9723 100644 --- a/tests/ui/cast/cast-rfc0401-2.stderr +++ b/tests/ui/cast/cast-rfc0401-2.stderr @@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-rfc0401-2.rs:6:13 | LL | let _ = 3 as bool; - | ^^^^^^^^^ help: compare with zero instead: `3 != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 3 != 0; + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/error-codes/E0054.stderr b/tests/ui/error-codes/E0054.stderr index ea81f4476a7..0a4adabbaf6 100644 --- a/tests/ui/error-codes/E0054.stderr +++ b/tests/ui/error-codes/E0054.stderr @@ -2,7 +2,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/E0054.rs:3:24 | LL | let x_is_nonzero = x as bool; - | ^^^^^^^^^ help: compare with zero instead: `x != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let x_is_nonzero = x != 0; + | ~~~~ error: aborting due to previous error diff --git a/tests/ui/error-festival.stderr b/tests/ui/error-festival.stderr index 74a2bc8d768..9d75671c4e6 100644 --- a/tests/ui/error-festival.stderr +++ b/tests/ui/error-festival.stderr @@ -63,7 +63,12 @@ error[E0054]: cannot cast `{integer}` as `bool` --> $DIR/error-festival.rs:33:24 | LL | let x_is_nonzero = x as bool; - | ^^^^^^^^^ help: compare with zero instead: `x != 0` + | ^^^^^^^^^ + | +help: compare with zero instead + | +LL | let x_is_nonzero = x != 0; + | ~~~~ error[E0606]: casting `&u8` as `u32` is invalid --> $DIR/error-festival.rs:37:18 diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 0cea60746bf..d63cec48917 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -86,7 +86,12 @@ error[E0054]: cannot cast `i32` as `bool` --> $DIR/cast-rfc0401.rs:39:13 | LL | let _ = 3_i32 as bool; - | ^^^^^^^^^^^^^ help: compare with zero instead: `3_i32 != 0` + | ^^^^^^^^^^^^^ + | +help: compare with zero instead + | +LL | let _ = 3_i32 != 0; + | ~~~~ error[E0054]: cannot cast `E` as `bool` --> $DIR/cast-rfc0401.rs:40:13