From 9e4ed337c783fab801d8a2e37feb58974205cfa3 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 29 Jan 2021 05:43:35 +0900 Subject: [PATCH] Suggest accessing field when code compiles with it --- .../src/infer/error_reporting/mod.rs | 41 +++++++++++++++++++ src/test/ui/suggestions/field-access.rs | 15 +++++++ src/test/ui/suggestions/field-access.stderr | 19 +++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/test/ui/suggestions/field-access.rs create mode 100644 src/test/ui/suggestions/field-access.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c39daea0811..68ffe3cd70f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1661,6 +1661,7 @@ enum Mismatch<'a> { debug!("exp_found {:?} terr {:?}", exp_found, terr); if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); + self.suggest_field_where_appropriate(cause, &exp_found, diag); self.suggest_await_on_expect_found(cause, span, &exp_found, diag); } @@ -1819,6 +1820,46 @@ fn suggest_await_on_expect_found( } } + fn suggest_field_where_appropriate( + &self, + cause: &ObligationCause<'tcx>, + exp_found: &ty::error::ExpectedFound>, + diag: &mut DiagnosticBuilder<'tcx>, + ) { + debug!("suggest_field_where_appropriate(cause={:?}, exp_found={:?})", cause, exp_found); + if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() { + if expected_def.is_enum() { + return; + } + + if let Some((name, ty)) = expected_def + .non_enum_variant() + .fields + .iter() + .filter(|field| field.vis.is_accessible_from(field.did, self.tcx)) + .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs))) + .inspect(|(name, ty)| { + debug!("suggest_field_where_appropriate: name={:?}, ty={:?}", name, ty) + }) + .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found)) + { + if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + diag.span_suggestion( + span, + &format!( + "you might have meant to use field `{}` of type `{}`", + name, ty + ), + format!("{}.{}", snippet, name), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, /// suggests it. fn suggest_as_ref_where_appropriate( diff --git a/src/test/ui/suggestions/field-access.rs b/src/test/ui/suggestions/field-access.rs new file mode 100644 index 00000000000..822f66f2a47 --- /dev/null +++ b/src/test/ui/suggestions/field-access.rs @@ -0,0 +1,15 @@ +struct A { + b: B, +} + +enum B { + Fst, + Snd, +} + +fn main() { + let a = A { b: B::Fst }; + if let B::Fst = a {}; + //~^ ERROR mismatched types [E0308] + // note: you might have meant to use field `b` of type `B` +} diff --git a/src/test/ui/suggestions/field-access.stderr b/src/test/ui/suggestions/field-access.stderr new file mode 100644 index 00000000000..58bc6d3f2da --- /dev/null +++ b/src/test/ui/suggestions/field-access.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/field-access.rs:12:12 + | +LL | Fst, + | --- unit variant defined here +... +LL | if let B::Fst = a {}; + | ^^^^^^ - this expression has type `A` + | | + | expected struct `A`, found enum `B` + | +help: you might have meant to use field `b` of type `B` + | +LL | if let B::Fst = a.b {}; + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. -- 2.44.0