Add "dereference boxed value" suggestion.

This commit adds a `help: consider dereferencing the boxed value`
suggestion to discriminants of match statements when the match arms have
type `T` and the discriminant has type `Box<T>`.
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 2995b25..35f6e6a 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -485,12 +485,29 @@
         }
     }
 
-    fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
+    fn note_error_origin(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+    ) {
         match cause.code {
             ObligationCauseCode::MatchExpressionArmPattern { span, ty } => {
                 if ty.is_suggestable() {  // don't show type `_`
                     err.span_label(span, format!("this match expression has type `{}`", ty));
                 }
+                if let Some(ty::error::ExpectedFound { found, .. }) = exp_found {
+                    if ty.is_box() && ty.boxed_ty() == found {
+                        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                            err.span_suggestion_with_applicability(
+                                span,
+                                "consider dereferencing the boxed value",
+                                format!("*{}", snippet),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    }
+                }
             }
             ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
@@ -1013,7 +1030,7 @@
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, &cause);
+        self.note_error_origin(diag, &cause, exp_found);
     }
 
     /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
diff --git a/src/test/ui/issues/issue-57741-1.rs b/src/test/ui/issues/issue-57741-1.rs
new file mode 100644
index 0000000..d0aae23
--- /dev/null
+++ b/src/test/ui/issues/issue-57741-1.rs
@@ -0,0 +1,18 @@
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion isn't made
+// because the box doesn't deref to the type of the arm.
+
+enum S {
+    A { a: usize },
+    B { b: usize },
+}
+
+fn main() {
+    let x = Box::new(3u32);
+    let y = match x {
+        S::A { a } | S::B { b: a } => a,
+        //~^ ERROR mismatched types [E0308]
+        //~^^ ERROR mismatched types [E0308]
+    };
+}
diff --git a/src/test/ui/issues/issue-57741-1.stderr b/src/test/ui/issues/issue-57741-1.stderr
new file mode 100644
index 0000000..d36424b
--- /dev/null
+++ b/src/test/ui/issues/issue-57741-1.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-57741-1.rs:14:9
+   |
+LL |     let y = match x {
+   |                   - this match expression has type `std::boxed::Box<u32>`
+LL |         S::A { a } | S::B { b: a } => a,
+   |         ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+   |
+   = note: expected type `std::boxed::Box<u32>`
+              found type `S`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57741-1.rs:14:22
+   |
+LL |     let y = match x {
+   |                   - this match expression has type `std::boxed::Box<u32>`
+LL |         S::A { a } | S::B { b: a } => a,
+   |                      ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+   |
+   = note: expected type `std::boxed::Box<u32>`
+              found type `S`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-57741.fixed b/src/test/ui/issues/issue-57741.fixed
new file mode 100644
index 0000000..4cae080
--- /dev/null
+++ b/src/test/ui/issues/issue-57741.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion is made and works.
+
+enum S {
+    A { a: usize },
+    B { b: usize },
+}
+
+enum T {
+    A(usize),
+    B(usize),
+}
+
+fn main() {
+    let x = Box::new(T::A(3));
+    let y = match *x {
+        T::A(a) | T::B(a) => a,
+        //~^ ERROR mismatched types [E0308]
+        //~^^ ERROR mismatched types [E0308]
+    };
+
+    let x = Box::new(S::A { a: 3 });
+    let y = match *x {
+        S::A { a } | S::B { b: a } => a,
+        //~^ ERROR mismatched types [E0308]
+        //~^^ ERROR mismatched types [E0308]
+    };
+}
diff --git a/src/test/ui/issues/issue-57741.rs b/src/test/ui/issues/issue-57741.rs
new file mode 100644
index 0000000..e265829
--- /dev/null
+++ b/src/test/ui/issues/issue-57741.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion is made and works.
+
+enum S {
+    A { a: usize },
+    B { b: usize },
+}
+
+enum T {
+    A(usize),
+    B(usize),
+}
+
+fn main() {
+    let x = Box::new(T::A(3));
+    let y = match x {
+        T::A(a) | T::B(a) => a,
+        //~^ ERROR mismatched types [E0308]
+        //~^^ ERROR mismatched types [E0308]
+    };
+
+    let x = Box::new(S::A { a: 3 });
+    let y = match x {
+        S::A { a } | S::B { b: a } => a,
+        //~^ ERROR mismatched types [E0308]
+        //~^^ ERROR mismatched types [E0308]
+    };
+}
diff --git a/src/test/ui/issues/issue-57741.stderr b/src/test/ui/issues/issue-57741.stderr
new file mode 100644
index 0000000..a26b1d20
--- /dev/null
+++ b/src/test/ui/issues/issue-57741.stderr
@@ -0,0 +1,59 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-57741.rs:20:9
+   |
+LL |     let y = match x {
+   |                   -
+   |                   |
+   |                   this match expression has type `std::boxed::Box<T>`
+   |                   help: consider dereferencing the boxed value: `*x`
+LL |         T::A(a) | T::B(a) => a,
+   |         ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
+   |
+   = note: expected type `std::boxed::Box<T>`
+              found type `T`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57741.rs:20:19
+   |
+LL |     let y = match x {
+   |                   -
+   |                   |
+   |                   this match expression has type `std::boxed::Box<T>`
+   |                   help: consider dereferencing the boxed value: `*x`
+LL |         T::A(a) | T::B(a) => a,
+   |                   ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
+   |
+   = note: expected type `std::boxed::Box<T>`
+              found type `T`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57741.rs:27:9
+   |
+LL |     let y = match x {
+   |                   -
+   |                   |
+   |                   this match expression has type `std::boxed::Box<S>`
+   |                   help: consider dereferencing the boxed value: `*x`
+LL |         S::A { a } | S::B { b: a } => a,
+   |         ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+   |
+   = note: expected type `std::boxed::Box<S>`
+              found type `S`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-57741.rs:27:22
+   |
+LL |     let y = match x {
+   |                   -
+   |                   |
+   |                   this match expression has type `std::boxed::Box<S>`
+   |                   help: consider dereferencing the boxed value: `*x`
+LL |         S::A { a } | S::B { b: a } => a,
+   |                      ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+   |
+   = note: expected type `std::boxed::Box<S>`
+              found type `S`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.