From f13fe5f3f7e2e2ed689967e818ffadc9cdba8af6 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 20 Jan 2019 20:26:46 +0100 Subject: [PATCH] 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`. --- src/librustc/infer/error_reporting/mod.rs | 21 +++++++- src/test/ui/issues/issue-57741-1.rs | 18 +++++++ src/test/ui/issues/issue-57741-1.stderr | 25 ++++++++++ src/test/ui/issues/issue-57741.fixed | 31 ++++++++++++ src/test/ui/issues/issue-57741.rs | 31 ++++++++++++ src/test/ui/issues/issue-57741.stderr | 59 +++++++++++++++++++++++ 6 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/issues/issue-57741-1.rs create mode 100644 src/test/ui/issues/issue-57741-1.stderr create mode 100644 src/test/ui/issues/issue-57741.fixed create mode 100644 src/test/ui/issues/issue-57741.rs create mode 100644 src/test/ui/issues/issue-57741.stderr diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 2995b25308d..35f6e6aa610 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -485,12 +485,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - 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>>, + ) { 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 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // 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 00000000000..d0aae23b2fc --- /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 00000000000..d36424b83b4 --- /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` +LL | S::A { a } | S::B { b: a } => a, + | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | + = note: expected type `std::boxed::Box` + 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` +LL | S::A { a } | S::B { b: a } => a, + | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | + = note: expected type `std::boxed::Box` + 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 00000000000..4cae080033c --- /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 00000000000..e2658295af7 --- /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 00000000000..a26b1d20ca3 --- /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` + | 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` + 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` + | 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` + 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` + | 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` + 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` + | 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` + found type `S` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`.