]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_hir_typeck / src / fn_ctxt / suggestions.rs
index 5fda4e191c2a003f447f0016f6659295de62a002..c4add4dbdfb2fb29038f464931cfe04bbabe71f1 100644 (file)
@@ -1,6 +1,6 @@
 use super::FnCtxt;
 
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
 use crate::fluent_generated as fluent;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -9,7 +9,8 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
+    AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath,
+    Stmt, StmtKind, TyKind, WherePredicate,
 };
 use rustc_hir_analysis::astconv::AstConv;
 use rustc_infer::traits::{self, StatementAsExpression};
@@ -274,13 +275,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) -> bool {
         let expr = expr.peel_blocks();
-        if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
-            self.check_ref(expr, found, expected)
+        if let Some((suggestion, msg, applicability, verbose, annotation)) =
+            self.suggest_deref_or_ref(expr, found, expected)
         {
             if verbose {
-                err.span_suggestion_verbose(sp, &msg, suggestion, applicability);
+                err.multipart_suggestion_verbose(msg, suggestion, applicability);
             } else {
-                err.span_suggestion(sp, &msg, suggestion, applicability);
+                err.multipart_suggestion(msg, suggestion, applicability);
             }
             if annotation {
                 let suggest_annotation = match expr.peel_drop_temps().kind {
@@ -342,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 err.span_label(sp, format!("{descr} `{name}` defined here"));
             }
             return true;
-        } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+        } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
             return true;
         } else {
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
@@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn suggest_boxing_when_appropriate(
         &self,
         err: &mut Diagnostic,
-        expr: &hir::Expr<'_>,
+        span: Span,
+        hir_id: HirId,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
     ) -> bool {
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return false;
-        }
-        if !expected.is_box() || found.is_box() {
+        // Do not suggest `Box::new` in const context.
+        if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
             return false;
         }
-        let boxed_found = self.tcx.mk_box(found);
-        if self.can_coerce(boxed_found, expected) {
-            err.multipart_suggestion(
-                "store this in the heap by calling `Box::new`",
-                vec![
-                    (expr.span.shrink_to_lo(), "Box::new(".to_string()),
-                    (expr.span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
-            );
-            err.note(
-                "for more on the distinction between the stack and the heap, read \
-                 https://doc.rust-lang.org/book/ch15-01-box.html, \
-                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
-                 https://doc.rust-lang.org/std/boxed/index.html",
-            );
+        if self.can_coerce(self.tcx.mk_box(found), expected) {
+            let suggest_boxing = match found.kind() {
+                ty::Tuple(tuple) if tuple.is_empty() => {
+                    SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
+                }
+                ty::Generator(def_id, ..)
+                    if matches!(
+                        self.tcx.generator_kind(def_id),
+                        Some(GeneratorKind::Async(AsyncGeneratorKind::Closure))
+                    ) =>
+                {
+                    SuggestBoxing::AsyncBody
+                }
+                _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() },
+            };
+            err.subdiagnostic(suggest_boxing);
+
             true
         } else {
             false
@@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         };
 
-        // get all where BoundPredicates here, because they are used in to cases below
+        // get all where BoundPredicates here, because they are used in two cases below
         let where_predicates = predicates
             .iter()
             .filter_map(|p| match p {
@@ -1096,10 +1096,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.tcx,
                 self.misc(expr.span),
                 self.param_env,
-                ty::Binder::dummy(self.tcx.mk_trait_ref(
+                ty::TraitRef::new(self.tcx,
                     into_def_id,
                     [expr_ty, expected_ty]
-                )),
+                ),
             ))
         {
             let sugg = if expr.precedence().order() >= PREC_POSTFIX {
@@ -1252,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
                 span,
             }) => {
-                let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; };
+                let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; };
                 if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
                     return false;
                 }
@@ -1311,7 +1311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // We have satisfied all requirements to provide a suggestion. Emit it.
         err.span_suggestion(
-            span,
+            *span,
             format!("if you meant to create a null pointer, use `{null_path_str}()`"),
             null_path_str + "()",
             Applicability::MachineApplicable,
@@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
         let item_ty = self.tcx.type_of(item.def_id).subst_identity();
         // FIXME(compiler-errors): This check is *so* rudimentary
-        if item_ty.needs_subst() {
+        if item_ty.has_param() {
             return false;
         }
         if self.can_coerce(item_ty, expected_ty) {
@@ -1438,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
             // Check that we're in fact trying to clone into the expected type
             && self.can_coerce(*pointee_ty, expected_ty)
-            && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
+            && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
             // And the expected type doesn't implement `Clone`
             && !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
                 self.tcx,
@@ -1449,7 +1449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             diag.span_note(
                 callee_expr.span,
-                &format!(
+                format!(
                     "`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
                 ),
             );