From 57291b8c5eea1ac59d5c54e65358b8dd56639c31 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Wed, 12 May 2021 19:25:12 +0200 Subject: [PATCH] Improve error message for non-exhaustive matches on non-exhaustive enums --- .../src/thir/pattern/check_match.rs | 11 +++++- .../auxiliary/match_non_exhaustive_lib.rs | 5 +++ src/test/ui/match/match_non_exhaustive.rs | 32 +++++++++++++++++ src/test/ui/match/match_non_exhaustive.stderr | 36 +++++++++++++++++++ .../ui/rfc-2008-non-exhaustive/enum.stderr | 6 ++-- .../uninhabited/match.stderr | 2 +- .../match_with_exhaustive_patterns.stderr | 2 +- 7 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/match/auxiliary/match_non_exhaustive_lib.rs create mode 100644 src/test/ui/match/match_non_exhaustive.rs create mode 100644 src/test/ui/match/match_non_exhaustive.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index fdecbb9478808..e4419070cbd08 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -496,12 +496,21 @@ fn non_exhaustive_match<'p, 'tcx>( err.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); }; + let is_variant_list_non_exhaustive = match scrut_ty.kind() { + ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did.is_local() => true, + _ => false, + }; + adt_defined_here(cx, &mut err, scrut_ty, &witnesses); err.help( "ensure that all possible cases are being handled, \ possibly by adding wildcards or more match arms", ); - err.note(&format!("the matched value is of type `{}`", scrut_ty)); + err.note(&format!( + "the matched value is of type `{}`{}", + scrut_ty, + if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" } + )); if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) && !is_empty_match && witnesses.len() == 1 diff --git a/src/test/ui/match/auxiliary/match_non_exhaustive_lib.rs b/src/test/ui/match/auxiliary/match_non_exhaustive_lib.rs new file mode 100644 index 0000000000000..3be72551e092f --- /dev/null +++ b/src/test/ui/match/auxiliary/match_non_exhaustive_lib.rs @@ -0,0 +1,5 @@ +#[non_exhaustive] +pub enum E1 {} + +#[non_exhaustive] +pub enum E2 { A, B } diff --git a/src/test/ui/match/match_non_exhaustive.rs b/src/test/ui/match/match_non_exhaustive.rs new file mode 100644 index 0000000000000..8219f0eb13571 --- /dev/null +++ b/src/test/ui/match/match_non_exhaustive.rs @@ -0,0 +1,32 @@ +// aux-build:match_non_exhaustive_lib.rs + +/* The error message for non-exhaustive matches on non-local enums + * marked as non-exhaustive should mention the fact that the enum + * is marked as non-exhaustive (issue #85227). + */ + +// Ignore non_exhaustive in the same crate +#[non_exhaustive] +enum L { A, B } + +extern crate match_non_exhaustive_lib; +use match_non_exhaustive_lib::{E1, E2}; + +fn foo() -> L {todo!()} +fn bar() -> (E1, E2) {todo!()} + +fn main() { + let l = foo(); + // No error for enums defined in this crate + match l { L::A => (), L::B => () }; + // (except if the match is already non-exhaustive) + match l { L::A => () }; + //~^ ERROR: non-exhaustive patterns: `B` not covered [E0004] + + // E1 is not visibly uninhabited from here + let (e1, e2) = bar(); + match e1 {}; + //~^ ERROR: non-exhaustive patterns: type `E1` is non-empty [E0004] + match e2 { E2::A => (), E2::B => () }; + //~^ ERROR: non-exhaustive patterns: `_` not covered [E0004] +} diff --git a/src/test/ui/match/match_non_exhaustive.stderr b/src/test/ui/match/match_non_exhaustive.stderr new file mode 100644 index 0000000000000..5debfe1c566c4 --- /dev/null +++ b/src/test/ui/match/match_non_exhaustive.stderr @@ -0,0 +1,36 @@ +error[E0004]: non-exhaustive patterns: `B` not covered + --> $DIR/match_non_exhaustive.rs:23:11 + | +LL | enum L { A, B } + | --------------- + | | | + | | not covered + | `L` defined here +... +LL | match l { L::A => () }; + | ^ pattern `B` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `L` + +error[E0004]: non-exhaustive patterns: type `E1` is non-empty + --> $DIR/match_non_exhaustive.rs:28:11 + | +LL | match e1 {}; + | ^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `E1`, which is marked as non-exhaustive + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/match_non_exhaustive.rs:30:11 + | +LL | match e2 { E2::A => (), E2::B => () }; + | ^^ pattern `_` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `E2`, which is marked as non-exhaustive + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index 1d1c43c9e8f49..cd9ded81e6a09 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -5,7 +5,7 @@ LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `EmptyNonExhaustiveEnum` + = note: the matched value is of type `EmptyNonExhaustiveEnum`, which is marked as non-exhaustive error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:16:11 @@ -14,7 +14,7 @@ LL | match enum_unit { | ^^^^^^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:23:11 @@ -23,7 +23,7 @@ LL | match enum_unit {}; | ^^^^^^^^^ pattern `_` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index 1f981ba82d083..746c1fd4aceb7 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -5,7 +5,7 @@ LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match.rs:23:11 diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index 0ff1c01cbdd0c..46e84dc09a3ea 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -5,7 +5,7 @@ LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum`, which is marked as non-exhaustive error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:26:11