From 5cc21d9051e421cab8ca271115b9a6d5ea927679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Sun, 2 May 2021 11:46:29 +0200 Subject: [PATCH] add suggestion for unit enum variant when matched with a patern --- .../rustc_resolve/src/late/diagnostics.rs | 43 +++++--- .../ui/empty/empty-struct-unit-pat.stderr | 102 +++++++++++++++--- src/test/ui/issues/issue-32004.stderr | 5 +- src/test/ui/issues/issue-pr29383.stderr | 10 +- .../match-pattern-field-mismatch-2.stderr | 5 +- .../ui/pattern/pattern-error-continue.stderr | 16 ++- src/test/ui/suggestions/issue-84700.rs | 26 +++++ src/test/ui/suggestions/issue-84700.stderr | 21 ++++ 8 files changed, 193 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/suggestions/issue-84700.rs create mode 100644 src/test/ui/suggestions/issue-84700.stderr diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e33c374f562e2..7561b3df3af70 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -819,6 +819,19 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { _ => false, }; + let find_span = |source: &PathSource<'_>, err: &mut DiagnosticBuilder<'_>| { + match source { + PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) + | PathSource::TupleStruct(span, _) => { + // We want the main underline to cover the suggested code as well for + // cleaner output. + err.set_span(*span); + *span + } + _ => span, + } + }; + let mut bad_struct_syntax_suggestion = |def_id: DefId| { let (followed_by_brace, closing_brace) = self.followed_by_brace(span); @@ -862,18 +875,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { - let span = match &source { - PathSource::Expr(Some(Expr { - span, kind: ExprKind::Call(_, _), .. - })) - | PathSource::TupleStruct(span, _) => { - // We want the main underline to cover the suggested code as well for - // cleaner output. - err.set_span(*span); - *span - } - _ => span, - }; + let span = find_span(&source, err); if let Some(span) = self.def_span(def_id) { err.span_label(span, &format!("`{}` defined here", path_str)); } @@ -1047,6 +1049,23 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { ) if ns == ValueNS => { bad_struct_syntax_suggestion(def_id); } + (Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => { + match source { + PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { + let span = find_span(&source, err); + if let Some(span) = self.def_span(def_id) { + err.span_label(span, &format!("`{}` defined here", path_str)); + } + err.span_suggestion( + span, + &format!("use this syntax instead"), + format!("{path_str}"), + Applicability::MaybeIncorrect, + ); + } + _ => return false, + } + } (Res::Def(DefKind::Ctor(_, CtorKind::Fn), def_id), _) if ns == ValueNS => { if let Some(span) = self.def_span(def_id) { err.span_label(span, &format!("`{}` defined here", path_str)); diff --git a/src/test/ui/empty/empty-struct-unit-pat.stderr b/src/test/ui/empty/empty-struct-unit-pat.stderr index 8ee14a3d01d89..a704e1fae497c 100644 --- a/src/test/ui/empty/empty-struct-unit-pat.stderr +++ b/src/test/ui/empty/empty-struct-unit-pat.stderr @@ -1,84 +1,154 @@ error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2` --> $DIR/empty-struct-unit-pat.rs:21:9 | +LL | struct Empty2; + | -------------- `Empty2` defined here +... LL | Empty2() => () - | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` + | ^^^^^^^^ | ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); | --------------------- similarly named tuple struct `XEmpty6` defined here + | +help: use this syntax instead + | +LL | Empty2 => () + | ^^^^^^ +help: a tuple struct with a similar name exists + | +LL | XEmpty6() => () + | ^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2` --> $DIR/empty-struct-unit-pat.rs:24:9 | LL | XEmpty2() => () - | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` + | ^^^^^^^^^ | - ::: $DIR/auxiliary/empty-struct.rs:3:1 + ::: $DIR/auxiliary/empty-struct.rs:2:1 | +LL | pub struct XEmpty2; + | ------------------- `XEmpty2` defined here LL | pub struct XEmpty6(); | --------------------- similarly named tuple struct `XEmpty6` defined here + | +help: use this syntax instead + | +LL | XEmpty2 => () + | ^^^^^^^ +help: a tuple struct with a similar name exists + | +LL | XEmpty6() => () + | ^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found unit struct `Empty2` --> $DIR/empty-struct-unit-pat.rs:28:9 | +LL | struct Empty2; + | -------------- `Empty2` defined here +... LL | Empty2(..) => () - | ^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` + | ^^^^^^^^^^ | ::: $DIR/auxiliary/empty-struct.rs:3:1 | LL | pub struct XEmpty6(); | --------------------- similarly named tuple struct `XEmpty6` defined here + | +help: use this syntax instead + | +LL | Empty2 => () + | ^^^^^^ +help: a tuple struct with a similar name exists + | +LL | XEmpty6(..) => () + | ^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found unit struct `XEmpty2` --> $DIR/empty-struct-unit-pat.rs:32:9 | LL | XEmpty2(..) => () - | ^^^^^^^ help: a tuple struct with a similar name exists: `XEmpty6` + | ^^^^^^^^^^^ | - ::: $DIR/auxiliary/empty-struct.rs:3:1 + ::: $DIR/auxiliary/empty-struct.rs:2:1 | +LL | pub struct XEmpty2; + | ------------------- `XEmpty2` defined here LL | pub struct XEmpty6(); | --------------------- similarly named tuple struct `XEmpty6` defined here + | +help: use this syntax instead + | +LL | XEmpty2 => () + | ^^^^^^^ +help: a tuple struct with a similar name exists + | +LL | XEmpty6(..) => () + | ^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4` --> $DIR/empty-struct-unit-pat.rs:37:9 | +LL | Empty4 + | ------ `E::Empty4` defined here +... LL | E::Empty4() => () - | ^^^^^^^^^ not a tuple struct or tuple variant + | ^^^^^^^^^^^ help: use this syntax instead: `E::Empty4` error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4` --> $DIR/empty-struct-unit-pat.rs:41:9 | LL | XE::XEmpty4() => (), - | ^^^^------- - | | - | help: a tuple variant with a similar name exists: `XEmpty5` + | ^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/empty-struct.rs:8:5 + ::: $DIR/auxiliary/empty-struct.rs:7:5 | +LL | XEmpty4, + | ------- `XE::XEmpty4` defined here LL | XEmpty5(), | --------- similarly named tuple variant `XEmpty5` defined here + | +help: use this syntax instead + | +LL | XE::XEmpty4 => (), + | ^^^^^^^^^^^ +help: a tuple variant with a similar name exists + | +LL | XE::XEmpty5() => (), + | ^^^^^^^ error[E0532]: expected tuple struct or tuple variant, found unit variant `E::Empty4` --> $DIR/empty-struct-unit-pat.rs:46:9 | +LL | Empty4 + | ------ `E::Empty4` defined here +... LL | E::Empty4(..) => () - | ^^^^^^^^^ not a tuple struct or tuple variant + | ^^^^^^^^^^^^^ help: use this syntax instead: `E::Empty4` error[E0532]: expected tuple struct or tuple variant, found unit variant `XE::XEmpty4` --> $DIR/empty-struct-unit-pat.rs:50:9 | LL | XE::XEmpty4(..) => (), - | ^^^^------- - | | - | help: a tuple variant with a similar name exists: `XEmpty5` + | ^^^^^^^^^^^^^^^ | - ::: $DIR/auxiliary/empty-struct.rs:8:5 + ::: $DIR/auxiliary/empty-struct.rs:7:5 | +LL | XEmpty4, + | ------- `XE::XEmpty4` defined here LL | XEmpty5(), | --------- similarly named tuple variant `XEmpty5` defined here + | +help: use this syntax instead + | +LL | XE::XEmpty4 => (), + | ^^^^^^^^^^^ +help: a tuple variant with a similar name exists + | +LL | XE::XEmpty5(..) => (), + | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/issues/issue-32004.stderr b/src/test/ui/issues/issue-32004.stderr index f95afb9c1fdc7..bf125a8942edf 100644 --- a/src/test/ui/issues/issue-32004.stderr +++ b/src/test/ui/issues/issue-32004.stderr @@ -21,8 +21,11 @@ LL | Foo::Baz => {} error[E0532]: expected tuple struct or tuple variant, found unit struct `S` --> $DIR/issue-32004.rs:16:9 | +LL | struct S; + | --------- `S` defined here +... LL | S(()) => {} - | ^ not a tuple struct or tuple variant + | ^^^^^ help: use this syntax instead: `S` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-pr29383.stderr b/src/test/ui/issues/issue-pr29383.stderr index e92fd6c2fdc5a..57783d75ba182 100644 --- a/src/test/ui/issues/issue-pr29383.stderr +++ b/src/test/ui/issues/issue-pr29383.stderr @@ -1,14 +1,20 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `E::A` --> $DIR/issue-pr29383.rs:9:14 | +LL | A, + | - `E::A` defined here +... LL | Some(E::A(..)) => {} - | ^^^^ not a tuple struct or tuple variant + | ^^^^^^^^ help: use this syntax instead: `E::A` error[E0532]: expected tuple struct or tuple variant, found unit variant `E::B` --> $DIR/issue-pr29383.rs:11:14 | +LL | B, + | - `E::B` defined here +... LL | Some(E::B(..)) => {} - | ^^^^ not a tuple struct or tuple variant + | ^^^^^^^^ help: use this syntax instead: `E::B` error: aborting due to 2 previous errors diff --git a/src/test/ui/match/match-pattern-field-mismatch-2.stderr b/src/test/ui/match/match-pattern-field-mismatch-2.stderr index cfffcd13851b8..ba32d0e99a471 100644 --- a/src/test/ui/match/match-pattern-field-mismatch-2.stderr +++ b/src/test/ui/match/match-pattern-field-mismatch-2.stderr @@ -1,8 +1,11 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `Color::NoColor` --> $DIR/match-pattern-field-mismatch-2.rs:12:11 | +LL | NoColor, + | ------- `Color::NoColor` defined here +... LL | Color::NoColor(_) => { } - | ^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | ^^^^^^^^^^^^^^^^^ help: use this syntax instead: `Color::NoColor` error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 497c93b29497c..44d6a854b3db6 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -9,11 +9,21 @@ error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` | LL | B(isize, isize), | --------------- similarly named tuple variant `B` defined here +LL | C(isize, isize, isize), +LL | D + | - `A::D` defined here ... LL | A::D(_) => (), - | ^^^- - | | - | help: a tuple variant with a similar name exists: `B` + | ^^^^^^^ + | +help: use this syntax instead + | +LL | A::D => (), + | ^^^^ +help: a tuple variant with a similar name exists + | +LL | A::B(_) => (), + | ^ error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields --> $DIR/pattern-error-continue.rs:17:9 diff --git a/src/test/ui/suggestions/issue-84700.rs b/src/test/ui/suggestions/issue-84700.rs new file mode 100644 index 0000000000000..a27169fdbb2d5 --- /dev/null +++ b/src/test/ui/suggestions/issue-84700.rs @@ -0,0 +1,26 @@ +// test for suggestion on fieldless enum variant + +#[derive(PartialEq, Debug)] +enum FarmAnimal { + Worm, + Cow, + Bull, + Chicken { num_eggs: usize }, + Dog (String), +} + +fn what_does_the_animal_say(animal: &FarmAnimal) { + + let noise = match animal { + FarmAnimal::Cow(_) => "moo".to_string(), + //~^ ERROR expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow` + FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(), + //~^ ERROR expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken` + FarmAnimal::Dog{..} => "woof!".to_string(), + _ => todo!() + }; + + println!("{:?} says: {:?}", animal, noise); +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-84700.stderr b/src/test/ui/suggestions/issue-84700.stderr new file mode 100644 index 0000000000000..b36d8aba36d30 --- /dev/null +++ b/src/test/ui/suggestions/issue-84700.stderr @@ -0,0 +1,21 @@ +error[E0532]: expected tuple struct or tuple variant, found unit variant `FarmAnimal::Cow` + --> $DIR/issue-84700.rs:15:9 + | +LL | Cow, + | --- `FarmAnimal::Cow` defined here +... +LL | FarmAnimal::Cow(_) => "moo".to_string(), + | ^^^^^^^^^^^^^^^^^^ help: use this syntax instead: `FarmAnimal::Cow` + +error[E0532]: expected tuple struct or tuple variant, found struct variant `FarmAnimal::Chicken` + --> $DIR/issue-84700.rs:17:9 + | +LL | Chicken { num_eggs: usize }, + | --------------------------- `FarmAnimal::Chicken` defined here +... +LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(), + | ^^^^^^^^^^^^^^^^^^^^^^ help: use struct pattern syntax instead: `FarmAnimal::Chicken { num_eggs }` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`.