Skip to content

Commit 21305f4

Browse files
committed
Auto merge of rust-lang#115270 - sebastiantoh:issue-105479, r=Nadrieril
Add note on non-exhaustiveness when matching on str and nested non-exhaustive enums Fixes rust-lang#105479 r? `@Nadrieril`
2 parents 2a1af89 + d87b87d commit 21305f4

File tree

11 files changed

+119
-41
lines changed

11 files changed

+119
-41
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -720,32 +720,31 @@ fn non_exhaustive_match<'p, 'tcx>(
720720
};
721721
};
722722

723-
let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
724-
ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
725-
726723
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
727-
err.note(format!(
728-
"the matched value is of type `{}`{}",
729-
scrut_ty,
730-
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
731-
));
724+
err.note(format!("the matched value is of type `{}`", scrut_ty));
732725

733726
if !is_empty_match && witnesses.len() == 1 {
734727
let mut non_exhaustive_tys = FxHashSet::default();
735728
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
736729

737730
for ty in non_exhaustive_tys {
738-
if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
731+
if ty.is_ptr_sized_integral() {
739732
err.note(format!(
740733
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
741-
exhaustively",
742-
));
734+
exhaustively",
735+
));
743736
if cx.tcx.sess.is_nightly_build() {
744737
err.help(format!(
745-
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
746-
enable precise `{ty}` matching",
747-
));
738+
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
739+
enable precise `{ty}` matching",
740+
));
748741
}
742+
} else if ty == cx.tcx.types.str_ {
743+
err.note(format!(
744+
"`&str` cannot be matched exhaustively, so a wildcard `_` is necessary",
745+
));
746+
} else if cx.is_foreign_non_exhaustive_enum(ty) {
747+
err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
749748
}
750749
}
751750
}

compiler/rustc_mir_build/src/thir/pattern/usefulness.rs

+26-23
Original file line numberDiff line numberDiff line change
@@ -618,10 +618,15 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
618618
let new_witnesses = if let Constructor::Missing { .. } = ctor {
619619
// We got the special `Missing` constructor, so each of the missing constructors
620620
// gives a new pattern that is not caught by the match. We list those patterns.
621-
let new_patterns = if pcx.is_non_exhaustive {
622-
// Here we don't want the user to try to list all variants, we want them to add
623-
// a wildcard, so we only suggest that.
624-
vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)]
621+
if pcx.is_non_exhaustive {
622+
witnesses
623+
.into_iter()
624+
// Here we don't want the user to try to list all variants, we want them to add
625+
// a wildcard, so we only suggest that.
626+
.map(|witness| {
627+
witness.apply_constructor(pcx, &Constructor::NonExhaustive)
628+
})
629+
.collect()
625630
} else {
626631
let mut split_wildcard = SplitWildcard::new(pcx);
627632
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
@@ -633,7 +638,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
633638
// constructor, that matches everything that can be built with
634639
// it. For example, if `ctor` is a `Constructor::Variant` for
635640
// `Option::Some`, we get the pattern `Some(_)`.
636-
let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard
641+
let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard
637642
.iter_missing(pcx)
638643
.filter_map(|missing_ctor| {
639644
// Check if this variant is marked `doc(hidden)`
@@ -648,27 +653,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
648653
.collect();
649654

650655
if hide_variant_show_wild {
651-
new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
656+
new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
652657
}
653658

654-
new
655-
};
656-
657-
witnesses
658-
.into_iter()
659-
.flat_map(|witness| {
660-
new_patterns.iter().map(move |pat| {
661-
Witness(
662-
witness
663-
.0
664-
.iter()
665-
.chain(once(pat))
666-
.map(DeconstructedPat::clone_and_forget_reachability)
667-
.collect(),
668-
)
659+
witnesses
660+
.into_iter()
661+
.flat_map(|witness| {
662+
new_patterns.iter().map(move |pat| {
663+
Witness(
664+
witness
665+
.0
666+
.iter()
667+
.chain(once(pat))
668+
.map(DeconstructedPat::clone_and_forget_reachability)
669+
.collect(),
670+
)
671+
})
669672
})
670-
})
671-
.collect()
673+
.collect()
674+
}
672675
} else {
673676
witnesses
674677
.into_iter()

tests/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ note: `E2` defined here
4545
|
4646
LL | pub enum E2 { A, B }
4747
| ^^^^^^^^^^^
48-
= note: the matched value is of type `E2`, which is marked as non-exhaustive
48+
= note: the matched value is of type `E2`
49+
= note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
4950
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
5051
|
5152
LL | let _e = || { match e2 { E2::A => (), E2::B => (), _ => todo!() } };

tests/ui/match/match_non_exhaustive.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ note: `E2` defined here
4545
|
4646
LL | pub enum E2 { A, B }
4747
| ^^^^^^^^^^^
48-
= note: the matched value is of type `E2`, which is marked as non-exhaustive
48+
= note: the matched value is of type `E2`
49+
= note: `E2` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
4950
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
5051
|
5152
LL | match e2 { E2::A => (), E2::B => (), _ => todo!() };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#[non_exhaustive]
2+
pub enum NonExhaustiveEnum { A, B }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn main() {
2+
let a = "";
3+
let b = "";
4+
match (a, b) {
5+
//~^ ERROR non-exhaustive patterns: `(&_, _)` not covered [E0004]
6+
//~| NOTE pattern `(&_, _)` not covered
7+
//~| NOTE the matched value is of type `(&str, &str)`
8+
//~| NOTE `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
9+
("a", "b") => {}
10+
("c", "d") => {}
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0004]: non-exhaustive patterns: `(&_, _)` not covered
2+
--> $DIR/issue-105479-str-non-exhaustiveness.rs:4:11
3+
|
4+
LL | match (a, b) {
5+
| ^^^^^^ pattern `(&_, _)` not covered
6+
|
7+
= note: the matched value is of type `(&str, &str)`
8+
= note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
9+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
10+
|
11+
LL ~ ("c", "d") => {},
12+
LL + (&_, _) => todo!()
13+
|
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0004`.

tests/ui/pattern/usefulness/issue-30240.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | match "world" {
55
| ^^^^^^^ pattern `&_` not covered
66
|
77
= note: the matched value is of type `&str`
8+
= note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
89
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
910
|
1011
LL ~ "hello" => {},
@@ -18,6 +19,7 @@ LL | match "world" {
1819
| ^^^^^^^ pattern `&_` not covered
1920
|
2021
= note: the matched value is of type `&str`
22+
= note: `&str` cannot be matched exhaustively, so a wildcard `_` is necessary
2123
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
2224
|
2325
LL ~ "hello" => {},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// aux-build:non-exhaustive.rs
2+
3+
extern crate non_exhaustive;
4+
5+
use non_exhaustive::NonExhaustiveEnum;
6+
7+
fn main() {
8+
match Some(NonExhaustiveEnum::A) {
9+
//~^ ERROR non-exhaustive patterns: `Some(_)` not covered [E0004]
10+
//~| NOTE pattern `Some(_)` not covered
11+
//~| NOTE `Option<NonExhaustiveEnum>` defined here
12+
//~| NOTE the matched value is of type `Option<NonExhaustiveEnum>`
13+
//~| NOTE `NonExhaustiveEnum` is marked as non-exhaustive
14+
Some(NonExhaustiveEnum::A) => {}
15+
Some(NonExhaustiveEnum::B) => {}
16+
None => {}
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
2+
--> $DIR/nested-non-exhaustive-enums.rs:8:11
3+
|
4+
LL | match Some(NonExhaustiveEnum::A) {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Some(_)` not covered
6+
|
7+
note: `Option<NonExhaustiveEnum>` defined here
8+
--> $SRC_DIR/core/src/option.rs:LL:COL
9+
::: $SRC_DIR/core/src/option.rs:LL:COL
10+
|
11+
= note: not covered
12+
= note: the matched value is of type `Option<NonExhaustiveEnum>`
13+
= note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
14+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
15+
|
16+
LL ~ None => {},
17+
LL + Some(_) => todo!()
18+
|
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0004`.

tests/ui/rfcs/rfc-2008-non-exhaustive/enum.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ note: `NonExhaustiveEnum` defined here
2828
|
2929
LL | pub enum NonExhaustiveEnum {
3030
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
31-
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
31+
= note: the matched value is of type `NonExhaustiveEnum`
32+
= note: `NonExhaustiveEnum` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively
3233
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
3334
|
3435
LL ~ NonExhaustiveEnum::Struct { .. } => "third",
@@ -46,7 +47,7 @@ note: `NonExhaustiveEnum` defined here
4647
|
4748
LL | pub enum NonExhaustiveEnum {
4849
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
49-
= note: the matched value is of type `NonExhaustiveEnum`, which is marked as non-exhaustive
50+
= note: the matched value is of type `NonExhaustiveEnum`
5051
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
5152
|
5253
LL ~ match enum_unit {

0 commit comments

Comments
 (0)