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_arena::TypedArena;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
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.
|
/// Report that a match is not exhaustive.
|
||||||
fn non_exhaustive_match<'p, 'tcx>(
|
fn non_exhaustive_match<'p, 'tcx>(
|
||||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||||
|
@ -717,22 +729,27 @@ fn non_exhaustive_match<'p, 'tcx>(
|
||||||
scrut_ty,
|
scrut_ty,
|
||||||
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
|
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
|
if !is_empty_match && witnesses.len() == 1 {
|
||||||
&& witnesses.len() == 1
|
let mut non_exhaustive_tys = FxHashSet::default();
|
||||||
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
|
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
|
||||||
{
|
|
||||||
err.note(format!(
|
for ty in non_exhaustive_tys {
|
||||||
"`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
if ty == cx.tcx.types.usize || ty == cx.tcx.types.isize {
|
||||||
exhaustively",
|
err.note(format!(
|
||||||
));
|
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
|
||||||
if cx.tcx.sess.is_nightly_build() {
|
exhaustively",
|
||||||
err.help(format!(
|
));
|
||||||
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
|
if cx.tcx.sess.is_nightly_build() {
|
||||||
enable precise `{scrut_ty}` matching",
|
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 let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
|
||||||
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
|
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
|
||||||
err.note("references are always considered inhabited");
|
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
|
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||||
|
|
|
|
||||||
= note: the matched value is of type `(usize, bool)`
|
= 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
|
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!() }
|
LL | match $s { $($t)+ => {}, (_, _) => todo!() }
|
||||||
|
@ -131,6 +133,8 @@ LL | m!((0isize, true), (isize::MIN..5, true)
|
||||||
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
|
||||||
|
|
|
|
||||||
= note: the matched value is of type `(isize, bool)`
|
= 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
|
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!() }
|
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 {
|
LL | struct Foo {
|
||||||
| ^^^
|
| ^^^
|
||||||
= note: the matched value is of type `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
|
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]) } => (),
|
LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
|
||||||
|
|
|
@ -10,6 +10,8 @@ note: `Foo` defined here
|
||||||
LL | struct Foo(isize, isize);
|
LL | struct Foo(isize, isize);
|
||||||
| ^^^
|
| ^^^
|
||||||
= note: the matched value is of type `Foo`
|
= 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
|
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),
|
LL ~ Foo(2, b) => println!("{}", b),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue