From d6ac50e54722efc02cec9d06037e004d14881e64 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 14 Apr 2024 09:10:57 -0400
Subject: [PATCH 1/4] Consolidate two copies of ty_kind_suggestion

---
 .../src/diagnostics/conflict_errors.rs        | 65 +---------------
 compiler/rustc_hir_analysis/src/check/mod.rs  | 74 +++----------------
 compiler/rustc_hir_typeck/src/expr.rs         |  6 +-
 .../src/traits/error_reporting/suggestions.rs | 58 +++++++++++++++
 4 files changed, 73 insertions(+), 130 deletions(-)

diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 48cd9c268a119..0a4f32c958502 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -671,68 +671,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         err
     }
 
-    fn ty_kind_suggestion(&self, ty: Ty<'tcx>) -> Option<String> {
-        // Keep in sync with `rustc_hir_analysis/src/check/mod.rs:ty_kind_suggestion`.
-        // FIXME: deduplicate the above.
-        let tcx = self.infcx.tcx;
-        let implements_default = |ty| {
-            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
-                return false;
-            };
-            self.infcx
-                .type_implements_trait(default_trait, [ty], self.param_env)
-                .must_apply_modulo_regions()
-        };
-
-        Some(match ty.kind() {
-            ty::Never | ty::Error(_) => return None,
-            ty::Bool => "false".to_string(),
-            ty::Char => "\'x\'".to_string(),
-            ty::Int(_) | ty::Uint(_) => "42".into(),
-            ty::Float(_) => "3.14159".into(),
-            ty::Slice(_) => "[]".to_string(),
-            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
-                "vec![]".to_string()
-            }
-            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
-                "String::new()".to_string()
-            }
-            ty::Adt(def, args) if def.is_box() => {
-                format!("Box::new({})", self.ty_kind_suggestion(args[0].expect_ty())?)
-            }
-            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
-                "None".to_string()
-            }
-            ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
-                format!("Ok({})", self.ty_kind_suggestion(args[0].expect_ty())?)
-            }
-            ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
-            ty::Ref(_, ty, mutability) => {
-                if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
-                    "\"\"".to_string()
-                } else {
-                    let Some(ty) = self.ty_kind_suggestion(*ty) else {
-                        return None;
-                    };
-                    format!("&{}{ty}", mutability.prefix_str())
-                }
-            }
-            ty::Array(ty, len) => format!(
-                "[{}; {}]",
-                self.ty_kind_suggestion(*ty)?,
-                len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
-            ),
-            ty::Tuple(tys) => format!(
-                "({})",
-                tys.iter()
-                    .map(|ty| self.ty_kind_suggestion(ty))
-                    .collect::<Option<Vec<String>>>()?
-                    .join(", ")
-            ),
-            _ => "value".to_string(),
-        })
-    }
-
     fn suggest_assign_value(
         &self,
         err: &mut Diag<'_>,
@@ -742,7 +680,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
         debug!("ty: {:?}, kind: {:?}", ty, ty.kind());
 
-        let Some(assign_value) = self.ty_kind_suggestion(ty) else {
+        let Some(assign_value) = self.infcx.err_ctxt().ty_kind_suggestion(self.param_env, ty)
+        else {
             return;
         };
 
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 024a0433b8cf6..eb0ffc19d4540 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -81,7 +81,6 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_errors::{pluralize, struct_span_code_err, Diag};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::Mutability;
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
@@ -96,8 +95,9 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
+use rustc_trait_selection::traits::error_reporting::suggestions::{
+    ReturnsVisitor, TypeErrCtxtExt as _,
+};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::ObligationCtxt;
 
@@ -467,67 +467,6 @@ fn fn_sig_suggestion<'tcx>(
     )
 }
 
-pub fn ty_kind_suggestion<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<String> {
-    // Keep in sync with `rustc_borrowck/src/diagnostics/conflict_errors.rs:ty_kind_suggestion`.
-    // FIXME: deduplicate the above.
-    let implements_default = |ty| {
-        let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
-            return false;
-        };
-        let infcx = tcx.infer_ctxt().build();
-        infcx
-            .type_implements_trait(default_trait, [ty], ty::ParamEnv::reveal_all())
-            .must_apply_modulo_regions()
-    };
-    Some(match ty.kind() {
-        ty::Never | ty::Error(_) => return None,
-        ty::Bool => "false".to_string(),
-        ty::Char => "\'x\'".to_string(),
-        ty::Int(_) | ty::Uint(_) => "42".into(),
-        ty::Float(_) => "3.14159".into(),
-        ty::Slice(_) => "[]".to_string(),
-        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
-            "vec![]".to_string()
-        }
-        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
-            "String::new()".to_string()
-        }
-        ty::Adt(def, args) if def.is_box() => {
-            format!("Box::new({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
-        }
-        ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
-            "None".to_string()
-        }
-        ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
-            format!("Ok({})", ty_kind_suggestion(args[0].expect_ty(), tcx)?)
-        }
-        ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
-        ty::Ref(_, ty, mutability) => {
-            if let (ty::Str, Mutability::Not) = (ty.kind(), mutability) {
-                "\"\"".to_string()
-            } else {
-                let Some(ty) = ty_kind_suggestion(*ty, tcx) else {
-                    return None;
-                };
-                format!("&{}{ty}", mutability.prefix_str())
-            }
-        }
-        ty::Array(ty, len) => format!(
-            "[{}; {}]",
-            ty_kind_suggestion(*ty, tcx)?,
-            len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
-        ),
-        ty::Tuple(tys) => format!(
-            "({})",
-            tys.iter()
-                .map(|ty| ty_kind_suggestion(ty, tcx))
-                .collect::<Option<Vec<String>>>()?
-                .join(", ")
-        ),
-        _ => "value".to_string(),
-    })
-}
-
 /// Return placeholder code for the given associated item.
 /// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
 /// structured suggestion.
@@ -562,7 +501,12 @@ fn suggestion_signature<'tcx>(
         }
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id).instantiate_identity();
-            let val = ty_kind_suggestion(ty, tcx).unwrap_or_else(|| "value".to_string());
+            let val = tcx
+                .infer_ctxt()
+                .build()
+                .err_ctxt()
+                .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
+                .unwrap_or_else(|| "value".to_string());
             format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 8f30c3fd37743..64590ca542d12 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -35,7 +35,6 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, HirId, QPath};
-use rustc_hir_analysis::check::ty_kind_suggestion;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -57,6 +56,7 @@ use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCauseCode};
@@ -694,7 +694,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                             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, tcx) {
+                            if let Some(val) =
+                                self.err_ctxt().ty_kind_suggestion(self.param_env, ty)
+                            {
                                 err.span_suggestion_verbose(
                                     expr.span.shrink_to_hi(),
                                     "give the `break` a value of the expected type",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 2067956d0f5f0..6ae7cbf717b12 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4540,6 +4540,64 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             Applicability::MachineApplicable,
         );
     }
+
+    fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<String> {
+        let tcx = self.infcx.tcx;
+        let implements_default = |ty| {
+            let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
+                return false;
+            };
+            self.type_implements_trait(default_trait, [ty], param_env).must_apply_modulo_regions()
+        };
+
+        Some(match ty.kind() {
+            ty::Never | ty::Error(_) => return None,
+            ty::Bool => "false".to_string(),
+            ty::Char => "\'x\'".to_string(),
+            ty::Int(_) | ty::Uint(_) => "42".into(),
+            ty::Float(_) => "3.14159".into(),
+            ty::Slice(_) => "[]".to_string(),
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Vec) => {
+                "vec![]".to_string()
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::String) => {
+                "String::new()".to_string()
+            }
+            ty::Adt(def, args) if def.is_box() => {
+                format!("Box::new({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
+            }
+            ty::Adt(def, _) if Some(def.did()) == tcx.get_diagnostic_item(sym::Option) => {
+                "None".to_string()
+            }
+            ty::Adt(def, args) if Some(def.did()) == tcx.get_diagnostic_item(sym::Result) => {
+                format!("Ok({})", self.ty_kind_suggestion(param_env, args[0].expect_ty())?)
+            }
+            ty::Adt(_, _) if implements_default(ty) => "Default::default()".to_string(),
+            ty::Ref(_, ty, mutability) => {
+                if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
+                    "\"\"".to_string()
+                } else {
+                    let Some(ty) = self.ty_kind_suggestion(param_env, *ty) else {
+                        return None;
+                    };
+                    format!("&{}{ty}", mutability.prefix_str())
+                }
+            }
+            ty::Array(ty, len) => format!(
+                "[{}; {}]",
+                self.ty_kind_suggestion(param_env, *ty)?,
+                len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
+            ),
+            ty::Tuple(tys) => format!(
+                "({})",
+                tys.iter()
+                    .map(|ty| self.ty_kind_suggestion(param_env, ty))
+                    .collect::<Option<Vec<String>>>()?
+                    .join(", ")
+            ),
+            _ => "value".to_string(),
+        })
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.

From e4c71f1fd8caf703dde7edb75b3cd33585aadddc Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 14 Apr 2024 09:21:38 -0400
Subject: [PATCH 2/4] Fix value suggestion for array in generic context

---
 compiler/rustc_trait_selection/src/lib.rs      |  1 +
 .../src/traits/error_reporting/suggestions.rs  |  8 +++-----
 tests/ui/consts/value-suggestion-ice-123906.rs |  8 ++++++++
 .../consts/value-suggestion-ice-123906.stderr  | 18 ++++++++++++++++++
 4 files changed, 30 insertions(+), 5 deletions(-)
 create mode 100644 tests/ui/consts/value-suggestion-ice-123906.rs
 create mode 100644 tests/ui/consts/value-suggestion-ice-123906.stderr

diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index b5fb710e4cc42..057d00aeae81e 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(extract_if)]
+#![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(option_take_if)]
 #![feature(never_type)]
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 6ae7cbf717b12..36fb5c8a6f7e8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4583,11 +4583,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     format!("&{}{ty}", mutability.prefix_str())
                 }
             }
-            ty::Array(ty, len) => format!(
-                "[{}; {}]",
-                self.ty_kind_suggestion(param_env, *ty)?,
-                len.eval_target_usize(tcx, ty::ParamEnv::reveal_all()),
-            ),
+            ty::Array(ty, len) if let Some(len) = len.try_eval_target_usize(tcx, param_env) => {
+                format!("[{}; {}]", self.ty_kind_suggestion(param_env, *ty)?, len)
+            }
             ty::Tuple(tys) => format!(
                 "({})",
                 tys.iter()
diff --git a/tests/ui/consts/value-suggestion-ice-123906.rs b/tests/ui/consts/value-suggestion-ice-123906.rs
new file mode 100644
index 0000000000000..531bbc158524a
--- /dev/null
+++ b/tests/ui/consts/value-suggestion-ice-123906.rs
@@ -0,0 +1,8 @@
+fn as_chunks<const N: usize>() -> [u8; N] {
+    loop {
+        break;
+        //~^ ERROR mismatched types
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/consts/value-suggestion-ice-123906.stderr b/tests/ui/consts/value-suggestion-ice-123906.stderr
new file mode 100644
index 0000000000000..8e2c316400d60
--- /dev/null
+++ b/tests/ui/consts/value-suggestion-ice-123906.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/value-suggestion-ice-123906.rs:3:9
+   |
+LL | fn as_chunks<const N: usize>() -> [u8; N] {
+   |                                   ------- expected `[u8; ]` because of this return type
+LL |     loop {
+   |     ---- this loop is expected to be of type `[u8; N]`
+LL |         break;
+   |         ^^^^^ expected `[u8; N]`, found `()`
+   |
+help: give the `break` a value of the expected type
+   |
+LL |         break value;
+   |               +++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.

From 4af94cfa05993786653416571fdfa56c6f68c489 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 14 Apr 2024 09:35:52 -0400
Subject: [PATCH 3/4] Suggest value on bare return

---
 compiler/rustc_hir_typeck/src/coercion.rs | 10 ++++++++++
 tests/ui/error-codes/E0069.stderr         |  5 +++++
 tests/ui/ret-non-nil.stderr               |  5 +++++
 tests/ui/return/suggest-a-value.rs        |  6 ++++++
 tests/ui/return/suggest-a-value.stderr    | 16 ++++++++++++++++
 5 files changed, 42 insertions(+)
 create mode 100644 tests/ui/return/suggest-a-value.rs
 create mode 100644 tests/ui/return/suggest-a-value.stderr

diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 720f4927ea892..079cca8240895 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -63,6 +63,7 @@ use rustc_span::DesugaringKind;
 use rustc_span::{BytePos, Span};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::TraitEngineExt as _;
@@ -1616,6 +1617,15 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             E0069,
                             "`return;` in a function whose return type is not `()`"
                         );
+                        if let Some(value) = fcx.err_ctxt().ty_kind_suggestion(fcx.param_env, found)
+                        {
+                            err.span_suggestion_verbose(
+                                cause.span.shrink_to_hi(),
+                                "give the `return` a value of the expected type",
+                                format!(" {value}"),
+                                Applicability::HasPlaceholders,
+                            );
+                        }
                         err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
diff --git a/tests/ui/error-codes/E0069.stderr b/tests/ui/error-codes/E0069.stderr
index 20ff8c258a004..ef6c411ae5892 100644
--- a/tests/ui/error-codes/E0069.stderr
+++ b/tests/ui/error-codes/E0069.stderr
@@ -5,6 +5,11 @@ LL | fn foo() -> u8 {
    |             -- expected `u8` because of this return type
 LL |     return;
    |     ^^^^^^ return type is not `()`
+   |
+help: give the `return` a value of the expected type
+   |
+LL |     return 42;
+   |            ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/ret-non-nil.stderr b/tests/ui/ret-non-nil.stderr
index 17567c6016a3a..802900e61a30e 100644
--- a/tests/ui/ret-non-nil.stderr
+++ b/tests/ui/ret-non-nil.stderr
@@ -5,6 +5,11 @@ LL | fn g() -> isize { return; }
    |           -----   ^^^^^^ return type is not `()`
    |           |
    |           expected `isize` because of this return type
+   |
+help: give the `return` a value of the expected type
+   |
+LL | fn g() -> isize { return 42; }
+   |                          ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/return/suggest-a-value.rs b/tests/ui/return/suggest-a-value.rs
new file mode 100644
index 0000000000000..7d23c0c44b781
--- /dev/null
+++ b/tests/ui/return/suggest-a-value.rs
@@ -0,0 +1,6 @@
+fn test() -> (i32,) {
+    return;
+    //~^ ERROR `return;` in a function whose return type is not `()`
+}
+
+fn main() {}
diff --git a/tests/ui/return/suggest-a-value.stderr b/tests/ui/return/suggest-a-value.stderr
new file mode 100644
index 0000000000000..3e0045a3ec4c6
--- /dev/null
+++ b/tests/ui/return/suggest-a-value.stderr
@@ -0,0 +1,16 @@
+error[E0069]: `return;` in a function whose return type is not `()`
+  --> $DIR/suggest-a-value.rs:2:5
+   |
+LL | fn test() -> (i32,) {
+   |              ------ expected `(i32,)` because of this return type
+LL |     return;
+   |     ^^^^^^ return type is not `()`
+   |
+help: give the `return` a value of the expected type
+   |
+LL |     return (42);
+   |            ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0069`.

From 325b24d7631b5da4806fedb542a3ae2971a30ea2 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Sun, 14 Apr 2024 09:41:16 -0400
Subject: [PATCH 4/4] Fix 1-tuple value suggestion

---
 .../src/traits/error_reporting/suggestions.rs            | 9 ++++-----
 tests/ui/return/suggest-a-value.stderr                   | 4 ++--
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 36fb5c8a6f7e8..48bb527c45d15 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -4577,9 +4577,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 if let (ty::Str, hir::Mutability::Not) = (ty.kind(), mutability) {
                     "\"\"".to_string()
                 } else {
-                    let Some(ty) = self.ty_kind_suggestion(param_env, *ty) else {
-                        return None;
-                    };
+                    let ty = self.ty_kind_suggestion(param_env, *ty)?;
                     format!("&{}{ty}", mutability.prefix_str())
                 }
             }
@@ -4587,11 +4585,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 format!("[{}; {}]", self.ty_kind_suggestion(param_env, *ty)?, len)
             }
             ty::Tuple(tys) => format!(
-                "({})",
+                "({}{})",
                 tys.iter()
                     .map(|ty| self.ty_kind_suggestion(param_env, ty))
                     .collect::<Option<Vec<String>>>()?
-                    .join(", ")
+                    .join(", "),
+                if tys.len() == 1 { "," } else { "" }
             ),
             _ => "value".to_string(),
         })
diff --git a/tests/ui/return/suggest-a-value.stderr b/tests/ui/return/suggest-a-value.stderr
index 3e0045a3ec4c6..573ade7b712d8 100644
--- a/tests/ui/return/suggest-a-value.stderr
+++ b/tests/ui/return/suggest-a-value.stderr
@@ -8,8 +8,8 @@ LL |     return;
    |
 help: give the `return` a value of the expected type
    |
-LL |     return (42);
-   |            ++++
+LL |     return (42,);
+   |            +++++
 
 error: aborting due to 1 previous error