From 978dc3d66f5e9a3bea733aca664e25b845fa0f27 Mon Sep 17 00:00:00 2001 From: Pramod Bisht Date: Fri, 19 Oct 2018 10:33:49 +0000 Subject: [PATCH] Fixed: Multiple errors on single typo in match pattern Here we have fixed the case where we were throwing two diagnostic messages `E0026` and `E0027` for same case like this Example error[E0026]: variant `A::A` does not have a field named `fob` --> src/test/ui/issue-52717.rs:20:12 | 20 | A::A { fob } => { println!("{}", fob); } | ^^^ variant `A::A` does not have this field error[E0027]: pattern does not mention field `foo` --> src/test/ui/issue-52717.rs:20:5 | 20 | A::A { fob } => { println!("{}", fob); } | ^^^^^^^^^^^^ missing field `foo` error: aborting due to 2 previous errors Here above we can see that both `E0026` and `E0027` are depicting same thing. So, to fix this issue, we are simply checking element of `inexistent_fields` is there any value lies in `unmentioned_fields` using Levenshtein algorithm, if does then for that case we are simply deleting element from `unmentioned_fields`. More or less now instead of showing separate message in `E0027` we are giving extra hint on `E0026` Address: #52717 --- src/librustc_typeck/check/_match.rs | 24 +++++++++++++++++------- src/test/ui/issue-52717.rs | 21 +++++++++++++++++++++ src/test/ui/issue-52717.stderr | 12 ++++++++++++ src/test/ui/issues/issue-17800.rs | 1 - src/test/ui/issues/issue-17800.stderr | 18 ++++++------------ 5 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/issue-52717.rs create mode 100644 src/test/ui/issue-52717.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index c9158af178fea..d623d3662e8b4 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -24,6 +24,7 @@ use std::cmp; use syntax::ast; use syntax::source_map::Spanned; use syntax::ptr::P; +use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -925,7 +926,11 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); self.check_pat_walk(&field.pat, field_ty, def_bm, true); } - + let mut unmentioned_fields = variant.fields + .iter() + .map(|field| field.ident.modern()) + .filter(|ident| !used_fields.contains_key(&ident)) + .collect::>(); if inexistent_fields.len() > 0 { let (field_names, t, plural) = if inexistent_fields.len() == 1 { (format!("a field named `{}`", inexistent_fields[0].1), "this", "") @@ -944,13 +949,23 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); kind_name, tcx.item_path_str(variant.did), field_names); - if let Some((span, _)) = inexistent_fields.last() { + if let Some((span, ident)) = inexistent_fields.last() { err.span_label(*span, format!("{} `{}` does not have {} field{}", kind_name, tcx.item_path_str(variant.did), t, plural)); + if plural == "" { + let input = unmentioned_fields.iter().map(|field| &field.name); + let suggested_name = + find_best_match_for_name(input, &ident.name.as_str(), None); + if let Some(suggested_name) = suggested_name { + err.span_suggestion(*span, "did you mean", suggested_name.to_string()); + // we don't want to throw `E0027` in case we have thrown `E0026` for them + unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); + } + } } if tcx.sess.teach(&err.get_code().unwrap()) { err.note( @@ -983,11 +998,6 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); tcx.sess.span_err(span, "`..` cannot be used in union patterns"); } } else if !etc { - let unmentioned_fields = variant.fields - .iter() - .map(|field| field.ident.modern()) - .filter(|ident| !used_fields.contains_key(&ident)) - .collect::>(); if unmentioned_fields.len() > 0 { let field_names = if unmentioned_fields.len() == 1 { format!("field `{}`", unmentioned_fields[0]) diff --git a/src/test/ui/issue-52717.rs b/src/test/ui/issue-52717.rs new file mode 100644 index 0000000000000..d40e2bd3d530c --- /dev/null +++ b/src/test/ui/issue-52717.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +enum A { + A { + foo: usize, + } +} + +fn main() { + let x = A::A { foo: 3 }; + match x { + A::A { fob } => { println!("{}", fob); } + } +} diff --git a/src/test/ui/issue-52717.stderr b/src/test/ui/issue-52717.stderr new file mode 100644 index 0000000000000..0ef5a84671d8d --- /dev/null +++ b/src/test/ui/issue-52717.stderr @@ -0,0 +1,12 @@ +error[E0026]: variant `A::A` does not have a field named `fob` + --> $DIR/issue-52717.rs:19:12 + | +LL | A::A { fob } => { println!("{}", fob); } + | ^^^ + | | + | variant `A::A` does not have this field + | help: did you mean: `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0026`. diff --git a/src/test/ui/issues/issue-17800.rs b/src/test/ui/issues/issue-17800.rs index f7cae91aa93a4..8ccf34f2456f4 100644 --- a/src/test/ui/issues/issue-17800.rs +++ b/src/test/ui/issues/issue-17800.rs @@ -17,7 +17,6 @@ fn main() { match MyOption::MySome(42) { MyOption::MySome { x: 42 } => (), //~^ ERROR variant `MyOption::MySome` does not have a field named `x` - //~| ERROR pattern does not mention field `0` _ => (), } } diff --git a/src/test/ui/issues/issue-17800.stderr b/src/test/ui/issues/issue-17800.stderr index 2cc562fbd7a1a..e1c48e8a0e8ef 100644 --- a/src/test/ui/issues/issue-17800.stderr +++ b/src/test/ui/issues/issue-17800.stderr @@ -2,17 +2,11 @@ error[E0026]: variant `MyOption::MySome` does not have a field named `x` --> $DIR/issue-17800.rs:18:28 | LL | MyOption::MySome { x: 42 } => (), - | ^^^^^ variant `MyOption::MySome` does not have this field + | ^^^^^ + | | + | variant `MyOption::MySome` does not have this field + | help: did you mean: `0` -error[E0027]: pattern does not mention field `0` - --> $DIR/issue-17800.rs:18:9 - | -LL | MyOption::MySome { x: 42 } => (), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `0` - | - = note: trying to match a tuple variant with a struct variant pattern - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0026, E0027. -For more information about an error, try `rustc --explain E0026`. +For more information about this error, try `rustc --explain E0026`.