From c9ad0e5c95a28440bf841981d07c64184b0d27a5 Mon Sep 17 00:00:00 2001 From: Muhtasim-Rasheed Date: Sun, 5 Jul 2026 19:53:22 +0600 Subject: [PATCH] Emit a suggestion to cast the never type into a concrete type when it fails to satisfy an `impl Trait` bound --- .../src/error_reporting/traits/suggestions.rs | 17 ++++++++++++++--- tests/ui/impl-trait/return-never-type.rs | 14 ++++++++++++++ tests/ui/impl-trait/return-never-type.stderr | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/ui/impl-trait/return-never-type.rs create mode 100644 tests/ui/impl-trait/return-never-type.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 139aa6bd77a87..9f5cfb39b9718 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4479,7 +4479,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); let expr = tcx.hir_expect_expr(hir_id); (expr_ty, expr) } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() @@ -4494,15 +4493,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && self.can_eq(param_env, pred.self_ty(), expr_ty) { - let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); (expr_ty, expr) } else { return; }; + let expr_ty_string = tcx.short_string(expr_ty, err.long_ty_path()); + if expr_ty.is_never() + && let span = expr.span.source_callsite() + && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) + && span != expr.span + { + err.span_suggestion( + span, + "`!` can be coerced to any type; consider casting it to a concrete type that implements the trait", + format!("{snippet} as /* Type */"), + Applicability::HasPlaceholders, + ); + } err.span_label( expr.span, with_forced_trimmed_paths!(format!( - "return type was inferred to be `{expr_ty}` here", + "return type was inferred to be `{expr_ty_string}` here", )), ); suggest_remove_deref(err, &expr); diff --git a/tests/ui/impl-trait/return-never-type.rs b/tests/ui/impl-trait/return-never-type.rs new file mode 100644 index 0000000000000..97ad2756dce71 --- /dev/null +++ b/tests/ui/impl-trait/return-never-type.rs @@ -0,0 +1,14 @@ +//@ edition:2024 + +#![feature(never_type)] + +use std::ops::Add; + +fn foo() -> impl Add { + //~^ ERROR cannot add `u32` to `!` + //~| HELP the trait `Add` is not implemented for `!` + unimplemented!() + //~^ HELP `!` can be coerced to any type; consider casting it to a concrete type that implements the trait +} + +fn main() {} diff --git a/tests/ui/impl-trait/return-never-type.stderr b/tests/ui/impl-trait/return-never-type.stderr new file mode 100644 index 0000000000000..dff06d7f41c98 --- /dev/null +++ b/tests/ui/impl-trait/return-never-type.stderr @@ -0,0 +1,18 @@ +error[E0277]: cannot add `u32` to `!` + --> $DIR/return-never-type.rs:7:13 + | +LL | fn foo() -> impl Add { + | ^^^^^^^^^^^^^ no implementation for `! + u32` +... +LL | unimplemented!() + | ---------------- return type was inferred to be `!` here + | + = help: the trait `Add` is not implemented for `!` +help: `!` can be coerced to any type; consider casting it to a concrete type that implements the trait + | +LL | unimplemented!() as /* Type */ + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.