Auto merge of #114397 - sebastiantoh:issue-85222, r=Nadrieril
Add note when matching on tuples/ADTs containing non-exhaustive types Fixes https://github.com/rust-lang/rust/issues/85222 r? `@Nadrieril`
This commit is contained in:
commit
c75b6bdb37
6 changed files with 276 additions and 14 deletions
|
@ -7,6 +7,7 @@ use crate::errors::*;
|
|||
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
|
@ -660,6 +661,17 @@ fn report_arm_reachability<'p, 'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_non_exhaustive_tys<'p, 'tcx>(
|
||||
pat: &DeconstructedPat<'p, 'tcx>,
|
||||
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
|
||||
) {
|
||||
if matches!(pat.ctor(), Constructor::NonExhaustive) {
|
||||
non_exhaustive_tys.insert(pat.ty());
|
||||
}
|
||||
pat.iter_fields()
|
||||
.for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
|
||||
}
|
||||
|
||||
/// Report that a match is not exhaustive.
|
||||
fn non_exhaustive_match<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
|
@ -717,22 +729,27 @@ fn non_exhaustive_match<'p, 'tcx>(
|
|||
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
|
||||
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
|
||||
{
|
||||
err.note(format!(
|
||||
"`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||
exhaustively",
|
||||
));
|
||||
if cx.tcx.sess.is_nightly_build() {
|
||||
err.help(format!(
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{scrut_ty}` matching",
|
||||
));
|
||||
|
||||
if !is_empty_match && witnesses.len() == 1 {
|
||||
let mut non_exhaustive_tys = FxHashSet::default();
|
||||
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
|
||||
|
||||
for ty in non_exhaustive_tys {
|
||||
if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
|
||||
err.note(format!(
|
||||
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||
exhaustively",
|
||||
));
|
||||
if cx.tcx.sess.is_nightly_build() {
|
||||
err.help(format!(
|
||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
||||
enable precise `{ty}` matching",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
|
||||
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
|
||||
err.note("references are always considered inhabited");
|
||||
|
|
|
@ -77,6 +77,8 @@ LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::
|
|||
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
|
|
||||
= note: the matched value is of type `(usize, bool)`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL | match $s { $($t)+ => {}, (_, _) => todo!() }
|
||||
|
@ -131,6 +133,8 @@ LL | m!((0isize, true), (isize::MIN..5, true)
|
|||
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
|
|
||||
= note: the matched value is of type `(isize, bool)`
|
||||
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL | match $s { $($t)+ => {}, (_, _) => todo!() }
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
struct A<T> {
|
||||
a: T,
|
||||
}
|
||||
|
||||
struct B<T, U>(T, U);
|
||||
|
||||
fn main() {
|
||||
match 0 {
|
||||
//~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
|
||||
0 => (),
|
||||
1..=usize::MAX => (),
|
||||
}
|
||||
|
||||
match (0usize, 0usize) {
|
||||
//~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
|
||||
(0, 0) => (),
|
||||
(1..=usize::MAX, 1..=usize::MAX) => (),
|
||||
}
|
||||
|
||||
match (0isize, 0usize) {
|
||||
//~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
|
||||
(isize::MIN..=isize::MAX, 0) => (),
|
||||
(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
|
||||
}
|
||||
|
||||
// Should not report note about usize not having fixed max value
|
||||
match Some(1usize) {
|
||||
//~^ ERROR non-exhaustive patterns: `Some(_)` not covered
|
||||
None => {}
|
||||
}
|
||||
|
||||
match Some(4) {
|
||||
//~^ ERROR non-exhaustive patterns: `Some(_)` not covered
|
||||
Some(0) => (),
|
||||
Some(1..=usize::MAX) => (),
|
||||
None => (),
|
||||
}
|
||||
|
||||
match Some(Some(Some(0))) {
|
||||
//~^ ERROR non-exhaustive patterns: `Some(Some(Some(_)))` not covered
|
||||
Some(Some(Some(0))) => (),
|
||||
Some(Some(Some(1..=usize::MAX))) => (),
|
||||
Some(Some(None)) => (),
|
||||
Some(None) => (),
|
||||
None => (),
|
||||
}
|
||||
|
||||
match (A { a: 0usize }) {
|
||||
//~^ ERROR non-exhaustive patterns: `A { .. }` not covered [E0004]
|
||||
A { a: 0 } => (),
|
||||
A { a: 1..=usize::MAX } => (),
|
||||
}
|
||||
|
||||
match B(0isize, 0usize) {
|
||||
//~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
|
||||
B(isize::MIN..=isize::MAX, 0) => (),
|
||||
B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
|
||||
}
|
||||
|
||||
// Should report only the note about usize not having fixed max value and not report
|
||||
// report the note about isize
|
||||
match B(0isize, 0usize) {
|
||||
//~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
|
||||
B(_, 0) => (),
|
||||
B(_, 1..=usize::MAX) => (),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:8:11
|
||||
|
|
||||
LL | match 0 {
|
||||
| ^ pattern `_` not covered
|
||||
|
|
||||
= note: the matched value is of type `usize`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ 1..=usize::MAX => (),
|
||||
LL ~ _ => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:14:11
|
||||
|
|
||||
LL | match (0usize, 0usize) {
|
||||
| ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
|
|
||||
= note: the matched value is of type `(usize, usize)`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ (1..=usize::MAX, 1..=usize::MAX) => (),
|
||||
LL ~ (_, _) => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:20:11
|
||||
|
|
||||
LL | match (0isize, 0usize) {
|
||||
| ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||
|
|
||||
= note: the matched value is of type `(isize, usize)`
|
||||
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ (isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
|
||||
LL ~ (_, _) => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:27:11
|
||||
|
|
||||
LL | match Some(1usize) {
|
||||
| ^^^^^^^^^^^^ pattern `Some(_)` not covered
|
||||
|
|
||||
note: `Option<usize>` defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
::: $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
|
||||
= note: not covered
|
||||
= note: the matched value is of type `Option<usize>`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ None => {},
|
||||
LL + Some(_) => todo!()
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:32:11
|
||||
|
|
||||
LL | match Some(4) {
|
||||
| ^^^^^^^ pattern `Some(_)` not covered
|
||||
|
|
||||
note: `Option<usize>` defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
::: $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
|
||||
= note: not covered
|
||||
= note: the matched value is of type `Option<usize>`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ None => (),
|
||||
LL ~ Some(_) => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Some(Some(Some(_)))` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:39:11
|
||||
|
|
||||
LL | match Some(Some(Some(0))) {
|
||||
| ^^^^^^^^^^^^^^^^^^^ pattern `Some(Some(Some(_)))` not covered
|
||||
|
|
||||
note: `Option<Option<Option<usize>>>` defined here
|
||||
--> $SRC_DIR/core/src/option.rs:LL:COL
|
||||
::: $SRC_DIR/core/src/option.rs:LL:COL
|
||||
|
|
||||
= note: not covered
|
||||
|
|
||||
= note: not covered
|
||||
|
|
||||
= note: not covered
|
||||
= note: the matched value is of type `Option<Option<Option<usize>>>`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ None => (),
|
||||
LL ~ Some(Some(Some(_))) => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `A { .. }` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:48:11
|
||||
|
|
||||
LL | match (A { a: 0usize }) {
|
||||
| ^^^^^^^^^^^^^^^^^ pattern `A { .. }` not covered
|
||||
|
|
||||
note: `A<usize>` defined here
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:1:8
|
||||
|
|
||||
LL | struct A<T> {
|
||||
| ^
|
||||
= note: the matched value is of type `A<usize>`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ A { a: 1..=usize::MAX } => (),
|
||||
LL ~ A { .. } => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:54:11
|
||||
|
|
||||
LL | match B(0isize, 0usize) {
|
||||
| ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
|
||||
|
|
||||
note: `B<isize, usize>` defined here
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
|
||||
|
|
||||
LL | struct B<T, U>(T, U);
|
||||
| ^
|
||||
= note: the matched value is of type `B<isize, usize>`
|
||||
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
|
||||
LL ~ B(_, _) => todo!(),
|
||||
|
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:62:11
|
||||
|
|
||||
LL | match B(0isize, 0usize) {
|
||||
| ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
|
||||
|
|
||||
note: `B<isize, usize>` defined here
|
||||
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
|
||||
|
|
||||
LL | struct B<T, U>(T, U);
|
||||
| ^
|
||||
= note: the matched value is of type `B<isize, usize>`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ B(_, 1..=usize::MAX) => (),
|
||||
LL ~ B(_, _) => todo!(),
|
||||
|
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
|
@ -10,6 +10,8 @@ note: `Foo` defined here
|
|||
LL | struct Foo {
|
||||
| ^^^
|
||||
= note: the matched value is of type `Foo`
|
||||
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
|
||||
|
|
|
@ -10,6 +10,8 @@ note: `Foo` defined here
|
|||
LL | struct Foo(isize, isize);
|
||||
| ^^^
|
||||
= note: the matched value is of type `Foo`
|
||||
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
|
||||
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ Foo(2, b) => println!("{}", b),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue