about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2021-11-06 23:12:04 +0100
committerGitHub <noreply@github.com>2021-11-06 23:12:04 +0100
commit1d9fe9cd0678ca0dd04573da08cc18503017a3fa (patch)
tree69b0579a935e17af7f0ff605883b3d5f2ae8923d /compiler
parent4c49db35fc671a522dbe07bfbeda8c7e7897108c (diff)
parentd93f7f93c44a7106071411224c0615c7cfcb2468 (diff)
downloadrust-1d9fe9cd0678ca0dd04573da08cc18503017a3fa.tar.gz
rust-1d9fe9cd0678ca0dd04573da08cc18503017a3fa.zip
Rollup merge of #90627 - camelid:suggest-box-deref, r=davidtwco
Suggest dereference of `Box` when inner type is expected

For example:

    enum Ty {
        Unit,
        List(Box<Ty>),
    }

    fn foo(x: Ty) -> Ty {
        match x {
            Ty::Unit => Ty::Unit,
            Ty::List(elem) => foo(elem),
        }
    }

Before, the only suggestion was to rewrap `inner` with `Ty::Wrapper`,
which is unhelpful and confusing:

    error[E0308]: mismatched types
     --> src/test/ui/suggestions/boxed-variant-field.rs:9:31
      |
    9 |         Ty::List(elem) => foo(elem),
      |                               ^^^^
      |                               |
      |                               expected enum `Ty`, found struct `Box`
      |                               help: try using a variant of the expected enum: `Ty::List(elem)`
      |
      = note: expected enum `Ty`
               found struct `Box<Ty>`

Now, rustc will first suggest dereferencing the `Box`, which is most
likely what the user intended:

    error[E0308]: mismatched types
     --> src/test/ui/suggestions/boxed-variant-field.rs:9:31
      |
    9 |         Ty::List(elem) => foo(elem),
      |                               ^^^^ expected enum `Ty`, found struct `Box`
      |
      = note: expected enum `Ty`
               found struct `Box<Ty>`
    help: try dereferencing the `Box`
      |
    9 |         Ty::List(elem) => foo(*elem),
      |                               +
    help: try using a variant of the expected enum
      |
    9 |         Ty::List(elem) => foo(Ty::List(elem)),
      |                               ~~~~~~~~~~~~~~

r? ``@davidtwco``
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs18
1 files changed, 18 insertions, 0 deletions
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 2b3672211e4..0cbbcdd1073 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -29,6 +29,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) {
         self.annotate_expected_due_to_let_ty(err, expr);
+        self.suggest_box_deref(err, expr, expected, expr_ty);
         self.suggest_compatible_variants(err, expr, expected, expr_ty);
         self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
         if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
@@ -167,6 +168,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggest_box_deref(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        expr_ty: Ty<'tcx>,
+    ) {
+        if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
+            err.span_suggestion_verbose(
+                expr.span.shrink_to_lo(),
+                "try dereferencing the `Box`",
+                "*".to_string(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(