Skip to content

Commit

Permalink
Point at uncovered variants in enum definition in note instead of a…
Browse files Browse the repository at this point in the history
… `span_label`

This makes the order of the output always consistent:

1. Place of the `match` missing arms
2. The `enum` definition span
3. The structured suggestion to add a fallthrough arm
  • Loading branch information
estebank committed Mar 8, 2022
1 parent 084ca79 commit ab4feea
Show file tree
Hide file tree
Showing 45 changed files with 1,033 additions and 696 deletions.
26 changes: 19 additions & 7 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Expand Up @@ -20,7 +20,7 @@ use rustc_session::lint::builtin::{
};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::{DesugaringKind, ExpnKind, Span};
use rustc_span::{DesugaringKind, ExpnKind, MultiSpan, Span};

crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match def_id.as_local() {
Expand Down Expand Up @@ -669,15 +669,27 @@ fn adt_defined_here<'p, 'tcx>(
) {
let ty = ty.peel_refs();
if let ty::Adt(def, _) = ty.kind() {
if let Some(sp) = cx.tcx.hir().span_if_local(def.did) {
err.span_label(sp, format!("`{}` defined here", ty));
}

if witnesses.len() < 4 {
let mut spans = vec![];
if witnesses.len() < 5 {
for sp in maybe_point_at_variant(cx, def, witnesses.iter()) {
err.span_label(sp, "not covered");
spans.push(sp);
}
}
let def_span = cx
.tcx
.hir()
.get_if_local(def.did)
.and_then(|node| node.ident())
.map(|ident| ident.span)
.unwrap_or_else(|| cx.tcx.def_span(def.did));
let mut span: MultiSpan =
if spans.is_empty() { def_span.into() } else { spans.clone().into() };

span.push_span_label(def_span, String::new());
for pat in spans {
span.push_span_label(pat, "not covered".to_string());
}
err.span_note(span, &format!("`{}` defined here", ty));
}
}

Expand Down
@@ -1,12 +1,14 @@
error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
--> $DIR/issue-88331.rs:11:20
|
LL | pub struct Opcode(pub u8);
| -------------------------- `Opcode` defined here
...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
|
note: `Opcode` defined here
--> $DIR/issue-88331.rs:4:12
|
LL | pub struct Opcode(pub u8);
| ^^^^^^
= note: the matched value is of type `Opcode`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand All @@ -17,12 +19,14 @@ LL ~ Opcode(0_u8) | Opcode(2_u8..=u8::MAX) => todo!(),
error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
--> $DIR/issue-88331.rs:27:20
|
LL | pub struct Opcode2(Opcode);
| --------------------------- `Opcode2` defined here
...
LL | move |i| match msg_type {
| ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
|
note: `Opcode2` defined here
--> $DIR/issue-88331.rs:18:12
|
LL | pub struct Opcode2(Opcode);
| ^^^^^^^
= note: the matched value is of type `Opcode2`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down
@@ -1,15 +1,14 @@
error[E0004]: non-exhaustive patterns: `B` not covered
--> $DIR/non-exhaustive-match.rs:26:25
|
LL | enum L1 { A, B }
| ----------------
| | |
| | not covered
| `L1` defined here
...
LL | let _b = || { match l1 { L1::A => () } };
| ^^ pattern `B` not covered
|
note: `L1` defined here
--> $DIR/non-exhaustive-match.rs:12:14
|
LL | enum L1 { A, B }
| -- ^ not covered
= note: the matched value is of type `L1`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand All @@ -22,6 +21,11 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
LL | let _d = || { match e1 {} };
| ^^
|
note: `E1` defined here
--> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
|
LL | pub enum E1 {}
| ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand All @@ -36,6 +40,11 @@ error[E0004]: non-exhaustive patterns: `_` not covered
LL | let _e = || { match e2 { E2::A => (), E2::B => () } };
| ^^ pattern `_` not covered
|
note: `E2` defined here
--> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
|
LL | pub enum E2 { A, B }
| ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down
19 changes: 9 additions & 10 deletions src/test/ui/empty/empty-never-array.stderr
@@ -1,19 +1,18 @@
error[E0005]: refutable pattern in local binding: `T(_, _)` not covered
--> $DIR/empty-never-array.rs:10:9
|
LL | / enum Helper<T, U> {
LL | | T(T, [!; 0]),
| | - not covered
LL | | #[allow(dead_code)]
LL | | U(U),
LL | | }
| |_- `Helper<T, U>` defined here
...
LL | let Helper::U(u) = Helper::T(t, []);
| ^^^^^^^^^^^^ pattern `T(_, _)` not covered
LL | let Helper::U(u) = Helper::T(t, []);
| ^^^^^^^^^^^^ pattern `T(_, _)` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Helper<T, U>` defined here
--> $DIR/empty-never-array.rs:4:5
|
LL | enum Helper<T, U> {
| ------
LL | T(T, [!; 0]),
| ^ not covered
= note: the matched value is of type `Helper<T, U>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
Expand Down
20 changes: 13 additions & 7 deletions src/test/ui/error-codes/E0004-2.stderr
Expand Up @@ -4,14 +4,20 @@ error[E0004]: non-exhaustive patterns: `None` and `Some(_)` not covered
LL | match x { }
| ^ patterns `None` and `Some(_)` not covered
|
::: $SRC_DIR/core/src/option.rs:LL:COL
|
LL | None,
| ---- not covered
...
LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
| ---- not covered
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | / pub enum Option<T> {
LL | | /// No value.
LL | | #[lang = "None"]
LL | | #[stable(feature = "rust1", since = "1.0.0")]
LL | | None,
| | ^^^^ not covered
... |
LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
| | ^^^^ not covered
LL | | }
| |_-
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down
18 changes: 9 additions & 9 deletions src/test/ui/error-codes/E0004.stderr
@@ -1,16 +1,16 @@
error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered
--> $DIR/E0004.rs:9:11
|
LL | / enum Terminator {
LL | | HastaLaVistaBaby,
| | ---------------- not covered
LL | | TalkToMyHand,
LL | | }
| |_- `Terminator` defined here
...
LL | match x {
| ^ pattern `HastaLaVistaBaby` not covered
LL | match x {
| ^ pattern `HastaLaVistaBaby` not covered
|
note: `Terminator` defined here
--> $DIR/E0004.rs:2:5
|
LL | enum Terminator {
| ----------
LL | HastaLaVistaBaby,
| ^^^^^^^^^^^^^^^^ not covered
= note: the matched value is of type `Terminator`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down
18 changes: 13 additions & 5 deletions src/test/ui/error-codes/E0005.stderr
Expand Up @@ -4,13 +4,21 @@ error[E0005]: refutable pattern in local binding: `None` not covered
LL | let Some(y) = x;
| ^^^^^^^ pattern `None` not covered
|
::: $SRC_DIR/core/src/option.rs:LL:COL
|
LL | None,
| ---- not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | / pub enum Option<T> {
LL | | /// No value.
LL | | #[lang = "None"]
LL | | #[stable(feature = "rust1", since = "1.0.0")]
LL | | None,
| | ^^^^ not covered
... |
LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
LL | | }
| |_-
= note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
Expand Down
16 changes: 12 additions & 4 deletions src/test/ui/error-codes/E0297.stderr
Expand Up @@ -4,11 +4,19 @@ error[E0005]: refutable pattern in `for` loop binding: `None` not covered
LL | for Some(x) in xs {}
| ^^^^^^^ pattern `None` not covered
|
::: $SRC_DIR/core/src/option.rs:LL:COL
|
LL | None,
| ---- not covered
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | / pub enum Option<T> {
LL | | /// No value.
LL | | #[lang = "None"]
LL | | #[stable(feature = "rust1", since = "1.0.0")]
LL | | None,
| | ^^^^ not covered
... |
LL | | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
LL | | }
| |_-
= note: the matched value is of type `Option<i32>`

error: aborting due to previous error
Expand Down
17 changes: 12 additions & 5 deletions src/test/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
Expand Up @@ -4,13 +4,20 @@ error[E0005]: refutable pattern in local binding: `Err(_)` not covered
LL | let Ok(_x) = foo();
| ^^^^^^ pattern `Err(_)` not covered
|
::: $SRC_DIR/core/src/result.rs:LL:COL
|
LL | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
| --- not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
note: `Result<u32, !>` defined here
--> $SRC_DIR/core/src/result.rs:LL:COL
|
LL | / pub enum Result<T, E> {
LL | | /// Contains the success value
LL | | #[lang = "Ok"]
LL | | #[stable(feature = "rust1", since = "1.0.0")]
... |
LL | | Err(#[stable(feature = "rust1", since = "1.0.0")] E),
| | ^^^ not covered
LL | | }
| |_-
= note: the matched value is of type `Result<u32, !>`
help: you might want to use `if let` to ignore the variant that isn't matched
|
Expand Down
21 changes: 15 additions & 6 deletions src/test/ui/match/match_non_exhaustive.stderr
@@ -1,15 +1,14 @@
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
|
note: `L` defined here
--> $DIR/match_non_exhaustive.rs:10:13
|
LL | enum L { A, B }
| - ^ not covered
= note: the matched value is of type `L`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand All @@ -22,6 +21,11 @@ error[E0004]: non-exhaustive patterns: type `E1` is non-empty
LL | match e1 {};
| ^^
|
note: `E1` defined here
--> $DIR/auxiliary/match_non_exhaustive_lib.rs:2:1
|
LL | pub enum E1 {}
| ^^^^^^^^^^^^^^
= note: the matched value is of type `E1`, which is marked as non-exhaustive
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand All @@ -36,6 +40,11 @@ error[E0004]: non-exhaustive patterns: `_` not covered
LL | match e2 { E2::A => (), E2::B => () };
| ^^ pattern `_` not covered
|
note: `E2` defined here
--> $DIR/auxiliary/match_non_exhaustive_lib.rs:5:1
|
LL | pub enum E2 { A, B }
| ^^^^^^^^^^^^^^^^^^^^
= note: the matched value is of type `E2`, which is marked as non-exhaustive
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down
14 changes: 7 additions & 7 deletions src/test/ui/pattern/usefulness/always-inhabited-union-ref.stderr
Expand Up @@ -16,14 +16,14 @@ LL + }
error[E0004]: non-exhaustive patterns: type `Foo` is non-empty
--> $DIR/always-inhabited-union-ref.rs:27:11
|
LL | / pub union Foo {
LL | | foo: !,
LL | | }
| |_- `Foo` defined here
...
LL | match uninhab_union() {
| ^^^^^^^^^^^^^^^
LL | match uninhab_union() {
| ^^^^^^^^^^^^^^^
|
note: `Foo` defined here
--> $DIR/always-inhabited-union-ref.rs:10:11
|
LL | pub union Foo {
| ^^^
= note: the matched value is of type `Foo`
help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
Expand Down

0 comments on commit ab4feea

Please sign in to comment.