about summary refs log tree commit diff
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
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``
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs18
-rw-r--r--src/test/ui/suggestions/boxed-variant-field.rs16
-rw-r--r--src/test/ui/suggestions/boxed-variant-field.stderr20
-rw-r--r--src/test/ui/terr-sorts.stderr4
4 files changed, 58 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(
diff --git a/src/test/ui/suggestions/boxed-variant-field.rs b/src/test/ui/suggestions/boxed-variant-field.rs
new file mode 100644
index 00000000000..d8f7fac1513
--- /dev/null
+++ b/src/test/ui/suggestions/boxed-variant-field.rs
@@ -0,0 +1,16 @@
+enum Ty {
+    Unit,
+    List(Box<Ty>),
+}
+
+fn foo(x: Ty) -> Ty {
+    match x {
+        Ty::Unit => Ty::Unit,
+        Ty::List(elem) => foo(elem),
+        //~^ ERROR mismatched types
+        //~| HELP try dereferencing the `Box`
+        //~| HELP try using a variant of the expected enum
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/boxed-variant-field.stderr b/src/test/ui/suggestions/boxed-variant-field.stderr
new file mode 100644
index 00000000000..d4ccb2ca490
--- /dev/null
+++ b/src/test/ui/suggestions/boxed-variant-field.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/boxed-variant-field.rs:9:31
+   |
+LL |         Ty::List(elem) => foo(elem),
+   |                               ^^^^ expected enum `Ty`, found struct `Box`
+   |
+   = note: expected enum `Ty`
+            found struct `Box<Ty>`
+help: try dereferencing the `Box`
+   |
+LL |         Ty::List(elem) => foo(*elem),
+   |                               +
+help: try using a variant of the expected enum
+   |
+LL |         Ty::List(elem) => foo(Ty::List(elem)),
+   |                               ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/terr-sorts.stderr b/src/test/ui/terr-sorts.stderr
index 869b3729659..65d90678040 100644
--- a/src/test/ui/terr-sorts.stderr
+++ b/src/test/ui/terr-sorts.stderr
@@ -6,6 +6,10 @@ LL |     want_foo(b);
    |
    = note: expected struct `Foo`
               found struct `Box<Foo>`
+help: try dereferencing the `Box`
+   |
+LL |     want_foo(*b);
+   |              +
 
 error: aborting due to previous error