From b84165ff7490ff6af17bddd1e43aebffdffa27d1 Mon Sep 17 00:00:00 2001 From: Robin Raymond Date: Wed, 29 May 2024 12:45:00 +0200 Subject: [PATCH 1/4] fix(issue-107165): Add failing test --- ...non_exhaustive_structs_and_variants_lib.rs | 7 +++ ...on-exhaustive-variant-hint-issue-107165.rs | 49 +++++++++++++++++++ ...xhaustive-variant-hint-issue-107165.stderr | 41 ++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 tests/ui/match/auxiliary/non_exhaustive_structs_and_variants_lib.rs create mode 100644 tests/ui/match/non-exhaustive-variant-hint-issue-107165.rs create mode 100644 tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr diff --git a/tests/ui/match/auxiliary/non_exhaustive_structs_and_variants_lib.rs b/tests/ui/match/auxiliary/non_exhaustive_structs_and_variants_lib.rs new file mode 100644 index 0000000000000..68ce670fb4677 --- /dev/null +++ b/tests/ui/match/auxiliary/non_exhaustive_structs_and_variants_lib.rs @@ -0,0 +1,7 @@ +pub enum Elibrary { + #[non_exhaustive] + Unit, + + #[non_exhaustive] + Tuple(i64), +} diff --git a/tests/ui/match/non-exhaustive-variant-hint-issue-107165.rs b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.rs new file mode 100644 index 0000000000000..7a4ef85cb0654 --- /dev/null +++ b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.rs @@ -0,0 +1,49 @@ +//@ aux-build:non_exhaustive_structs_and_variants_lib.rs + +/* Provide a hint to the user that a match of a non-exhaustive variant might + * fail because of a missing struct pattern (issue #107165). + */ + +// Ignore non_exhaustive in the same crate +enum Elocal { + #[non_exhaustive] + Unit, + + #[non_exhaustive] + Tuple(i64), +} + +extern crate non_exhaustive_structs_and_variants_lib; +use non_exhaustive_structs_and_variants_lib::Elibrary; + +fn local() -> Elocal { + todo!() +} + +fn library() -> Elibrary { + todo!() +} + +fn main() { + let loc = local(); + // No error for enums defined in this crate + match loc { + Elocal::Unit => (), + Elocal::Tuple(_) => (), + }; + + // Elibrary is externally defined + let lib = library(); + + match lib { + Elibrary::Unit => (), + //~^ ERROR unit variant `Unit` is private [E0603] + _ => (), + }; + + match lib { + Elibrary::Tuple(_) => (), + //~^ ERROR tuple variant `Tuple` is private [E0603] + _ => (), + }; +} diff --git a/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr new file mode 100644 index 0000000000000..cbebf048e6313 --- /dev/null +++ b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr @@ -0,0 +1,41 @@ +error[E0603]: unit variant `Unit` is private + --> $DIR/non-exhaustive-variant-hint-issue-107165.rs:39:19 + | +LL | Elibrary::Unit => (), + | ^^^^ private unit variant + | +note: the unit variant `Unit` is defined here + --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:3:5 + | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` +LL | Unit, + | ^^^^ +help: consider using a struct pattern instead: `Unit { .. }` + --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:3:5 + | +LL | Unit, + | ^^^^ + +error[E0603]: tuple variant `Tuple` is private + --> $DIR/non-exhaustive-variant-hint-issue-107165.rs:45:19 + | +LL | Elibrary::Tuple(_) => (), + | ^^^^^ private tuple variant + | +note: the tuple variant `Tuple` is defined here + --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:6:5 + | +LL | #[non_exhaustive] + | ----------------- cannot be constructed because it is `#[non_exhaustive]` +LL | Tuple(i64), + | ^^^^^ +help: consider using a struct pattern instead: `Tuple { .. }` + --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:6:5 + | +LL | Tuple(i64), + | ^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0603`. From d52fcc57d8ded8bc0d295f885cdf3dfec907c3fe Mon Sep 17 00:00:00 2001 From: Robin Raymond Date: Wed, 29 May 2024 12:45:27 +0200 Subject: [PATCH 2/4] fix(issue-107165): Add suggestion to use struct syntax --- compiler/rustc_resolve/src/diagnostics.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 856cfbc01e8cd..1b6b7e22bbb6a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1896,6 +1896,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Final step in the import chain, point out if the ADT is `non_exhaustive` // which is probably why this privacy violation occurred. + let mut err_help = None; if next_binding.is_none() && let Some(span) = non_exhaustive { @@ -1903,6 +1904,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { span, "cannot be constructed because it is `#[non_exhaustive]`", ); + err_help = + Some(format!("consider using a struct pattern instead: `{ident} {{ .. }}`")); } let note = errors::NoteAndRefersToTheItemDefinedHere { span: note_span, @@ -1912,6 +1915,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { dots: next_binding.is_some(), }; err.subdiagnostic(self.tcx.dcx(), note); + if let Some(err_help) = err_help { + err.span_help(def_span, err_help); + } } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); From bd5ae056048c4745e68fffb7e2b6fadbb0b84e0e Mon Sep 17 00:00:00 2001 From: Robin Raymond Date: Wed, 29 May 2024 13:11:19 +0200 Subject: [PATCH 3/4] fix(issue-107165): Reference correct span --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- .../non-exhaustive-variant-hint-issue-107165.stderr | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1b6b7e22bbb6a..0e8176755aca5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1916,7 +1916,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }; err.subdiagnostic(self.tcx.dcx(), note); if let Some(err_help) = err_help { - err.span_help(def_span, err_help); + err.span_help(ident.span, err_help); } } // We prioritize shorter paths, non-core imports and direct imports over the alternatives. diff --git a/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr index cbebf048e6313..9689841e59b76 100644 --- a/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr +++ b/tests/ui/match/non-exhaustive-variant-hint-issue-107165.stderr @@ -12,10 +12,10 @@ LL | #[non_exhaustive] LL | Unit, | ^^^^ help: consider using a struct pattern instead: `Unit { .. }` - --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:3:5 + --> $DIR/non-exhaustive-variant-hint-issue-107165.rs:39:19 | -LL | Unit, - | ^^^^ +LL | Elibrary::Unit => (), + | ^^^^ error[E0603]: tuple variant `Tuple` is private --> $DIR/non-exhaustive-variant-hint-issue-107165.rs:45:19 @@ -31,10 +31,10 @@ LL | #[non_exhaustive] LL | Tuple(i64), | ^^^^^ help: consider using a struct pattern instead: `Tuple { .. }` - --> $DIR/auxiliary/non_exhaustive_structs_and_variants_lib.rs:6:5 + --> $DIR/non-exhaustive-variant-hint-issue-107165.rs:45:19 | -LL | Tuple(i64), - | ^^^^^ +LL | Elibrary::Tuple(_) => (), + | ^^^^^ error: aborting due to 2 previous errors From d89eb11b6dea54d567474243043616166f591e15 Mon Sep 17 00:00:00 2001 From: Robin Raymond Date: Wed, 29 May 2024 13:14:07 +0200 Subject: [PATCH 4/4] fix(issue-107165): Bless other ui files --- .../rfc-2008-non-exhaustive/struct.stderr | 10 ++++++++ .../rfc-2008-non-exhaustive/variant.stderr | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr index 39b1ef1e078c7..034a3a09bf7f6 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/struct.stderr @@ -17,6 +17,11 @@ LL | #[non_exhaustive] | ----------------- cannot be constructed because it is `#[non_exhaustive]` LL | pub struct TupleStruct(pub u16, pub u16); | ^^^^^^^^^^^^^^^^^^^^^^ +help: consider using a struct pattern instead: `TupleStruct { .. }` + --> $DIR/struct.rs:23:32 + | +LL | let ts_explicit = structs::TupleStruct(640, 480); + | ^^^^^^^^^^^ error[E0603]: unit struct `UnitStruct` is private --> $DIR/struct.rs:32:32 @@ -31,6 +36,11 @@ LL | #[non_exhaustive] | ----------------- cannot be constructed because it is `#[non_exhaustive]` LL | pub struct UnitStruct; | ^^^^^^^^^^^^^^^^^^^^^ +help: consider using a struct pattern instead: `UnitStruct { .. }` + --> $DIR/struct.rs:32:32 + | +LL | let us_explicit = structs::UnitStruct; + | ^^^^^^^^^^ error[E0639]: cannot create non-exhaustive struct using struct expression --> $DIR/struct.rs:7:14 diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr index 4083f57a9cdf9..8f908c5fc03a0 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/variant.stderr @@ -11,6 +11,11 @@ LL | #[non_exhaustive] Tuple(u32), | ----------------- ^^^^^ | | | cannot be constructed because it is `#[non_exhaustive]` +help: consider using a struct pattern instead: `Tuple { .. }` + --> $DIR/variant.rs:11:48 + | +LL | let variant_tuple = NonExhaustiveVariants::Tuple(640); + | ^^^^^ error[E0603]: unit variant `Unit` is private --> $DIR/variant.rs:14:47 @@ -25,6 +30,11 @@ LL | #[non_exhaustive] Unit, | ----------------- ^^^^ | | | cannot be constructed because it is `#[non_exhaustive]` +help: consider using a struct pattern instead: `Unit { .. }` + --> $DIR/variant.rs:14:47 + | +LL | let variant_unit = NonExhaustiveVariants::Unit; + | ^^^^ error[E0603]: unit variant `Unit` is private --> $DIR/variant.rs:18:32 @@ -39,6 +49,11 @@ LL | #[non_exhaustive] Unit, | ----------------- ^^^^ | | | cannot be constructed because it is `#[non_exhaustive]` +help: consider using a struct pattern instead: `Unit { .. }` + --> $DIR/variant.rs:18:32 + | +LL | NonExhaustiveVariants::Unit => "", + | ^^^^ error[E0603]: tuple variant `Tuple` is private --> $DIR/variant.rs:20:32 @@ -53,6 +68,11 @@ LL | #[non_exhaustive] Tuple(u32), | ----------------- ^^^^^ | | | cannot be constructed because it is `#[non_exhaustive]` +help: consider using a struct pattern instead: `Tuple { .. }` + --> $DIR/variant.rs:20:32 + | +LL | NonExhaustiveVariants::Tuple(fe_tpl) => "", + | ^^^^^ error[E0603]: tuple variant `Tuple` is private --> $DIR/variant.rs:26:35 @@ -67,6 +87,11 @@ LL | #[non_exhaustive] Tuple(u32), | ----------------- ^^^^^ | | | cannot be constructed because it is `#[non_exhaustive]` +help: consider using a struct pattern instead: `Tuple { .. }` + --> $DIR/variant.rs:26:35 + | +LL | if let NonExhaustiveVariants::Tuple(fe_tpl) = variant_struct { + | ^^^^^ error[E0639]: cannot create non-exhaustive variant using struct expression --> $DIR/variant.rs:8:26