From dcbe85abad8ddd3a39fcafe70a884db4e71f0b03 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 2 Jul 2020 02:37:52 +0900 Subject: [PATCH 1/2] Explain exhaustive matching on {usize,isize} maximum values --- .../hair/pattern/check_match.rs | 10 +++++++- ...-gate-precise_pointer_size_matching.stderr | 4 +++ ...non-exhaustive-pattern-pointer-size-int.rs | 21 ++++++++++++++++ ...exhaustive-pattern-pointer-size-int.stderr | 25 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs create mode 100644 src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index 6fc447a87f57a..6a68c91588944 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -468,6 +468,7 @@ fn check_exhaustive<'p, 'tcx>( // In the case of an empty match, replace the '`_` not covered' diagnostic with something more // informative. let mut err; + let joined_patterns = joined_uncovered_patterns(&witnesses); if is_empty_match && !non_empty_enum { err = create_e0004( cx.tcx.sess, @@ -475,7 +476,6 @@ fn check_exhaustive<'p, 'tcx>( format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), ); } else { - let joined_patterns = joined_uncovered_patterns(&witnesses); err = create_e0004( cx.tcx.sess, sp, @@ -490,6 +490,14 @@ fn check_exhaustive<'p, 'tcx>( possibly by adding wildcards or more match arms", ); err.note(&format!("the matched value is of type `{}`", scrut_ty)); + if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) + && joined_patterns == "`_`" + { + err.note("for `usize` and `isize`, no assumptions about the maximum value are permitted"); + err.note( + "to exhaustively match on either pointer-size integer type, wildcards must be used", + ); + } err.emit(); } diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index 6c5d0091c5add..8aa1534b27689 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -6,6 +6,8 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `usize` + = note: for `usize` and `isize`, no assumptions about the maximum value are permitted + = note: to exhaustively match on either pointer-size integer type, wildcards must be used error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11 @@ -15,6 +17,8 @@ LL | match 0isize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `isize` + = note: for `usize` and `isize`, no assumptions about the maximum value are permitted + = note: to exhaustively match on either pointer-size integer type, wildcards must be used error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs new file mode 100644 index 0000000000000..aa6a3ffc522ef --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs @@ -0,0 +1,21 @@ +use std::{usize, isize}; + +fn main() { + match 0usize { + //~^ ERROR non-exhaustive patterns + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `usize` + //~| NOTE for `usize` and `isize`, no assumptions about the maximum value are permitted + //~| NOTE to exhaustively match on either pointer-size integer type, wildcards must be used + 0 ..= usize::MAX => {} + } + + match 0isize { + //~^ ERROR non-exhaustive patterns + //~| NOTE pattern `_` not covered + //~| NOTE the matched value is of type `isize` + //~| NOTE for `usize` and `isize`, no assumptions about the maximum value are permitted + //~| NOTE to exhaustively match on either pointer-size integer type, wildcards must be used + isize::MIN ..= isize::MAX => {} + } +} diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr new file mode 100644 index 0000000000000..cd47e74fa4643 --- /dev/null +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr @@ -0,0 +1,25 @@ +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:4:11 + | +LL | match 0usize { + | ^^^^^^ 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 `usize` + = note: for `usize` and `isize`, no assumptions about the maximum value are permitted + = note: to exhaustively match on either pointer-size integer type, wildcards must be used + +error[E0004]: non-exhaustive patterns: `_` not covered + --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:13:11 + | +LL | match 0isize { + | ^^^^^^ 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 `isize` + = note: for `usize` and `isize`, no assumptions about the maximum value are permitted + = note: to exhaustively match on either pointer-size integer type, wildcards must be used + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. From b93ecc1dacd3d534b0fa24e4b14cd3b07bae9889 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 5 Jul 2020 03:40:59 +0900 Subject: [PATCH 2/2] Address code reviews --- .../hair/pattern/check_match.rs | 25 +++++++++++++------ ...-gate-precise_pointer_size_matching.stderr | 8 +++--- ...non-exhaustive-pattern-pointer-size-int.rs | 10 +++++--- ...exhaustive-pattern-pointer-size-int.stderr | 21 +++++++++++----- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index 6a68c91588944..4bfb6cccbcb30 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_session::config::nightly_options; use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; use rustc_session::parse::feature_err; @@ -468,7 +469,6 @@ fn check_exhaustive<'p, 'tcx>( // In the case of an empty match, replace the '`_` not covered' diagnostic with something more // informative. let mut err; - let joined_patterns = joined_uncovered_patterns(&witnesses); if is_empty_match && !non_empty_enum { err = create_e0004( cx.tcx.sess, @@ -476,6 +476,7 @@ fn check_exhaustive<'p, 'tcx>( format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), ); } else { + let joined_patterns = joined_uncovered_patterns(&witnesses); err = create_e0004( cx.tcx.sess, sp, @@ -487,16 +488,26 @@ fn check_exhaustive<'p, 'tcx>( 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", + possibly by adding wildcards or more match arms", ); err.note(&format!("the matched value is of type `{}`", scrut_ty)); if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) - && joined_patterns == "`_`" + && !is_empty_match + && witnesses.len() == 1 + && witnesses[0].is_wildcard() { - err.note("for `usize` and `isize`, no assumptions about the maximum value are permitted"); - err.note( - "to exhaustively match on either pointer-size integer type, wildcards must be used", - ); + err.note(&format!( + "`{}` does not have a fixed maximum value, \ + so a wildcard `_` is necessary to match exhaustively", + scrut_ty, + )); + if nightly_options::is_nightly_build() { + err.help(&format!( + "add `#![feature(precise_pointer_size_matching)]` \ + to the crate attributes to enable precise `{}` matching", + scrut_ty, + )); + } } err.emit(); } diff --git a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index 8aa1534b27689..c7a63e5d50252 100644 --- a/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/src/test/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -6,8 +6,8 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `usize` - = note: for `usize` and `isize`, no assumptions about the maximum value are permitted - = note: to exhaustively match on either pointer-size integer type, wildcards must be used + = 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 error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11 @@ -17,8 +17,8 @@ LL | match 0isize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `isize` - = note: for `usize` and `isize`, no assumptions about the maximum value are permitted - = note: to exhaustively match on either pointer-size integer type, wildcards must be used + = 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 error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs index aa6a3ffc522ef..0c52876e21f95 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.rs @@ -5,8 +5,7 @@ fn main() { //~^ ERROR non-exhaustive patterns //~| NOTE pattern `_` not covered //~| NOTE the matched value is of type `usize` - //~| NOTE for `usize` and `isize`, no assumptions about the maximum value are permitted - //~| NOTE to exhaustively match on either pointer-size integer type, wildcards must be used + //~| NOTE `usize` does not have a fixed maximum value 0 ..= usize::MAX => {} } @@ -14,8 +13,11 @@ fn main() { //~^ ERROR non-exhaustive patterns //~| NOTE pattern `_` not covered //~| NOTE the matched value is of type `isize` - //~| NOTE for `usize` and `isize`, no assumptions about the maximum value are permitted - //~| NOTE to exhaustively match on either pointer-size integer type, wildcards must be used + //~| NOTE `isize` does not have a fixed maximum value isize::MIN ..= isize::MAX => {} } + + match 7usize {} + //~^ ERROR non-exhaustive patterns + //~| NOTE the matched value is of type `usize` } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr index cd47e74fa4643..d0aa452fd3861 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-pointer-size-int.stderr @@ -6,20 +6,29 @@ LL | match 0usize { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `usize` - = note: for `usize` and `isize`, no assumptions about the maximum value are permitted - = note: to exhaustively match on either pointer-size integer type, wildcards must be used + = 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 error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:13:11 + --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:12:11 | LL | match 0isize { | ^^^^^^ 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 `isize` - = note: for `usize` and `isize`, no assumptions about the maximum value are permitted - = note: to exhaustively match on either pointer-size integer type, wildcards must be used + = 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 -error: aborting due to 2 previous errors +error[E0004]: non-exhaustive patterns: type `usize` is non-empty + --> $DIR/non-exhaustive-pattern-pointer-size-int.rs:20:11 + | +LL | match 7usize {} + | ^^^^^^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `usize` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0004`.