Skip to content

Commit 7fc6365

Browse files
committedNov 1, 2023
Auto merge of #116692 - Nadrieril:half-open-ranges, r=cjgillot
Match usize/isize exhaustively with half-open ranges The long-awaited finale to the saga of [exhaustiveness checking for integers](#50912)! ```rust match 0usize { 0.. => {} // exhaustive! } match 0usize { 0..usize::MAX => {} // helpful error message! } ``` Features: - Half-open ranges behave as expected for `usize`/`isize`; - Trying to use `0..usize::MAX` will tell you that `usize::MAX..` is missing and explain why. No more unhelpful "`_` is missing"; - Everything else stays the same. This should unblock #37854. Review-wise: - I recommend looking commit-by-commit; - This regresses perf because of the added complexity in `IntRange`; hopefully not too much; - I measured each `#[inline]`, they all help a bit with the perf regression (tho I don't get why); - I did not touch MIR building; I expect there's an easy PR there that would skip unnecessary comparisons when the range is half-open.
2 parents 98f5ebb + 35fe75d commit 7fc6365

26 files changed

+898
-597
lines changed
 

‎compiler/rustc_middle/src/thir.rs

+239-10
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@ use rustc_hir::RangeEnd;
1616
use rustc_index::newtype_index;
1717
use rustc_index::IndexVec;
1818
use rustc_middle::middle::region;
19-
use rustc_middle::mir::interpret::AllocId;
19+
use rustc_middle::mir::interpret::{AllocId, Scalar};
2020
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
2121
use rustc_middle::ty::adjustment::PointerCoercion;
22+
use rustc_middle::ty::layout::IntegerExt;
2223
use rustc_middle::ty::{
2324
self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty,
24-
UpvarArgs,
25+
TyCtxt, UpvarArgs,
2526
};
2627
use rustc_span::def_id::LocalDefId;
2728
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
28-
use rustc_target::abi::{FieldIdx, VariantIdx};
29+
use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx};
2930
use rustc_target::asm::InlineAsmRegOrRegClass;
31+
use std::cmp::Ordering;
3032
use std::fmt;
3133
use std::ops::Index;
3234

@@ -810,12 +812,243 @@ pub enum PatKind<'tcx> {
810812
Error(ErrorGuaranteed),
811813
}
812814

815+
/// A range pattern.
816+
/// The boundaries must be of the same type and that type must be numeric.
813817
#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)]
814818
pub struct PatRange<'tcx> {
815-
pub lo: mir::Const<'tcx>,
816-
pub hi: mir::Const<'tcx>,
819+
pub lo: PatRangeBoundary<'tcx>,
820+
pub hi: PatRangeBoundary<'tcx>,
817821
#[type_visitable(ignore)]
818822
pub end: RangeEnd,
823+
pub ty: Ty<'tcx>,
824+
}
825+
826+
impl<'tcx> PatRange<'tcx> {
827+
/// Whether this range covers the full extent of possible values (best-effort, we ignore floats).
828+
#[inline]
829+
pub fn is_full_range(&self, tcx: TyCtxt<'tcx>) -> Option<bool> {
830+
let (min, max, size, bias) = match *self.ty.kind() {
831+
ty::Char => (0, std::char::MAX as u128, Size::from_bits(32), 0),
832+
ty::Int(ity) => {
833+
let size = Integer::from_int_ty(&tcx, ity).size();
834+
let max = size.truncate(u128::MAX);
835+
let bias = 1u128 << (size.bits() - 1);
836+
(0, max, size, bias)
837+
}
838+
ty::Uint(uty) => {
839+
let size = Integer::from_uint_ty(&tcx, uty).size();
840+
let max = size.unsigned_int_max();
841+
(0, max, size, 0)
842+
}
843+
_ => return None,
844+
};
845+
846+
// We want to compare ranges numerically, but the order of the bitwise representation of
847+
// signed integers does not match their numeric order. Thus, to correct the ordering, we
848+
// need to shift the range of signed integers to correct the comparison. This is achieved by
849+
// XORing with a bias (see pattern/deconstruct_pat.rs for another pertinent example of this
850+
// pattern).
851+
//
852+
// Also, for performance, it's important to only do the second `try_to_bits` if necessary.
853+
let lo_is_min = match self.lo {
854+
PatRangeBoundary::NegInfinity => true,
855+
PatRangeBoundary::Finite(value) => {
856+
let lo = value.try_to_bits(size).unwrap() ^ bias;
857+
lo <= min
858+
}
859+
PatRangeBoundary::PosInfinity => false,
860+
};
861+
if lo_is_min {
862+
let hi_is_max = match self.hi {
863+
PatRangeBoundary::NegInfinity => false,
864+
PatRangeBoundary::Finite(value) => {
865+
let hi = value.try_to_bits(size).unwrap() ^ bias;
866+
hi > max || hi == max && self.end == RangeEnd::Included
867+
}
868+
PatRangeBoundary::PosInfinity => true,
869+
};
870+
if hi_is_max {
871+
return Some(true);
872+
}
873+
}
874+
Some(false)
875+
}
876+
877+
#[inline]
878+
pub fn contains(
879+
&self,
880+
value: mir::Const<'tcx>,
881+
tcx: TyCtxt<'tcx>,
882+
param_env: ty::ParamEnv<'tcx>,
883+
) -> Option<bool> {
884+
use Ordering::*;
885+
debug_assert_eq!(self.ty, value.ty());
886+
let ty = self.ty;
887+
let value = PatRangeBoundary::Finite(value);
888+
// For performance, it's important to only do the second comparison if necessary.
889+
Some(
890+
match self.lo.compare_with(value, ty, tcx, param_env)? {
891+
Less | Equal => true,
892+
Greater => false,
893+
} && match value.compare_with(self.hi, ty, tcx, param_env)? {
894+
Less => true,
895+
Equal => self.end == RangeEnd::Included,
896+
Greater => false,
897+
},
898+
)
899+
}
900+
901+
#[inline]
902+
pub fn overlaps(
903+
&self,
904+
other: &Self,
905+
tcx: TyCtxt<'tcx>,
906+
param_env: ty::ParamEnv<'tcx>,
907+
) -> Option<bool> {
908+
use Ordering::*;
909+
debug_assert_eq!(self.ty, other.ty);
910+
// For performance, it's important to only do the second comparison if necessary.
911+
Some(
912+
match other.lo.compare_with(self.hi, self.ty, tcx, param_env)? {
913+
Less => true,
914+
Equal => self.end == RangeEnd::Included,
915+
Greater => false,
916+
} && match self.lo.compare_with(other.hi, self.ty, tcx, param_env)? {
917+
Less => true,
918+
Equal => other.end == RangeEnd::Included,
919+
Greater => false,
920+
},
921+
)
922+
}
923+
}
924+
925+
impl<'tcx> fmt::Display for PatRange<'tcx> {
926+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
927+
if let PatRangeBoundary::Finite(value) = &self.lo {
928+
write!(f, "{value}")?;
929+
}
930+
if let PatRangeBoundary::Finite(value) = &self.hi {
931+
write!(f, "{}", self.end)?;
932+
write!(f, "{value}")?;
933+
} else {
934+
// `0..` is parsed as an inclusive range, we must display it correctly.
935+
write!(f, "..")?;
936+
}
937+
Ok(())
938+
}
939+
}
940+
941+
/// A (possibly open) boundary of a range pattern.
942+
/// If present, the const must be of a numeric type.
943+
#[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
944+
pub enum PatRangeBoundary<'tcx> {
945+
Finite(mir::Const<'tcx>),
946+
NegInfinity,
947+
PosInfinity,
948+
}
949+
950+
impl<'tcx> PatRangeBoundary<'tcx> {
951+
#[inline]
952+
pub fn is_finite(self) -> bool {
953+
matches!(self, Self::Finite(..))
954+
}
955+
#[inline]
956+
pub fn as_finite(self) -> Option<mir::Const<'tcx>> {
957+
match self {
958+
Self::Finite(value) => Some(value),
959+
Self::NegInfinity | Self::PosInfinity => None,
960+
}
961+
}
962+
#[inline]
963+
pub fn to_const(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> mir::Const<'tcx> {
964+
match self {
965+
Self::Finite(value) => value,
966+
Self::NegInfinity => {
967+
// Unwrap is ok because the type is known to be numeric.
968+
let c = ty.numeric_min_val(tcx).unwrap();
969+
mir::Const::from_ty_const(c, tcx)
970+
}
971+
Self::PosInfinity => {
972+
// Unwrap is ok because the type is known to be numeric.
973+
let c = ty.numeric_max_val(tcx).unwrap();
974+
mir::Const::from_ty_const(c, tcx)
975+
}
976+
}
977+
}
978+
pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
979+
match self {
980+
Self::Finite(value) => value.eval_bits(tcx, param_env),
981+
Self::NegInfinity => {
982+
// Unwrap is ok because the type is known to be numeric.
983+
ty.numeric_min_and_max_as_bits(tcx).unwrap().0
984+
}
985+
Self::PosInfinity => {
986+
// Unwrap is ok because the type is known to be numeric.
987+
ty.numeric_min_and_max_as_bits(tcx).unwrap().1
988+
}
989+
}
990+
}
991+
992+
#[instrument(skip(tcx, param_env), level = "debug", ret)]
993+
pub fn compare_with(
994+
self,
995+
other: Self,
996+
ty: Ty<'tcx>,
997+
tcx: TyCtxt<'tcx>,
998+
param_env: ty::ParamEnv<'tcx>,
999+
) -> Option<Ordering> {
1000+
use PatRangeBoundary::*;
1001+
match (self, other) {
1002+
// When comparing with infinities, we must remember that `0u8..` and `0u8..=255`
1003+
// describe the same range. These two shortcuts are ok, but for the rest we must check
1004+
// bit values.
1005+
(PosInfinity, PosInfinity) => return Some(Ordering::Equal),
1006+
(NegInfinity, NegInfinity) => return Some(Ordering::Equal),
1007+
1008+
// This code is hot when compiling matches with many ranges. So we
1009+
// special-case extraction of evaluated scalars for speed, for types where
1010+
// raw data comparisons are appropriate. E.g. `unicode-normalization` has
1011+
// many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
1012+
// in this way.
1013+
(Finite(mir::Const::Ty(a)), Finite(mir::Const::Ty(b)))
1014+
if matches!(ty.kind(), ty::Uint(_) | ty::Char) =>
1015+
{
1016+
return Some(a.kind().cmp(&b.kind()));
1017+
}
1018+
(
1019+
Finite(mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _)),
1020+
Finite(mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _)),
1021+
) if matches!(ty.kind(), ty::Uint(_) | ty::Char) => return Some(a.cmp(&b)),
1022+
_ => {}
1023+
}
1024+
1025+
let a = self.eval_bits(ty, tcx, param_env);
1026+
let b = other.eval_bits(ty, tcx, param_env);
1027+
1028+
match ty.kind() {
1029+
ty::Float(ty::FloatTy::F32) => {
1030+
use rustc_apfloat::Float;
1031+
let a = rustc_apfloat::ieee::Single::from_bits(a);
1032+
let b = rustc_apfloat::ieee::Single::from_bits(b);
1033+
a.partial_cmp(&b)
1034+
}
1035+
ty::Float(ty::FloatTy::F64) => {
1036+
use rustc_apfloat::Float;
1037+
let a = rustc_apfloat::ieee::Double::from_bits(a);
1038+
let b = rustc_apfloat::ieee::Double::from_bits(b);
1039+
a.partial_cmp(&b)
1040+
}
1041+
ty::Int(ity) => {
1042+
use rustc_middle::ty::layout::IntegerExt;
1043+
let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size();
1044+
let a = size.sign_extend(a) as i128;
1045+
let b = size.sign_extend(b) as i128;
1046+
Some(a.cmp(&b))
1047+
}
1048+
ty::Uint(_) | ty::Char => Some(a.cmp(&b)),
1049+
_ => bug!(),
1050+
}
1051+
}
8191052
}
8201053

8211054
impl<'tcx> fmt::Display for Pat<'tcx> {
@@ -944,11 +1177,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
9441177
PatKind::InlineConstant { def: _, ref subpattern } => {
9451178
write!(f, "{} (from inline const)", subpattern)
9461179
}
947-
PatKind::Range(box PatRange { lo, hi, end }) => {
948-
write!(f, "{lo}")?;
949-
write!(f, "{end}")?;
950-
write!(f, "{hi}")
951-
}
1180+
PatKind::Range(ref range) => write!(f, "{range}"),
9521181
PatKind::Slice { ref prefix, ref slice, ref suffix }
9531182
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
9541183
write!(f, "[")?;

‎compiler/rustc_middle/src/ty/util.rs

+43-35
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_index::bit_set::GrowableBitSet;
1919
use rustc_macros::HashStable;
2020
use rustc_session::Limit;
2121
use rustc_span::sym;
22-
use rustc_target::abi::{Integer, IntegerType, Size};
22+
use rustc_target::abi::{Integer, IntegerType, Primitive, Size};
2323
use rustc_target::spec::abi::Abi;
2424
use smallvec::SmallVec;
2525
use std::{fmt, iter};
@@ -919,54 +919,62 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for OpaqueTypeExpander<'tcx> {
919919
}
920920

921921
impl<'tcx> Ty<'tcx> {
922+
/// Returns the `Size` for primitive types (bool, uint, int, char, float).
923+
pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size {
924+
match *self.kind() {
925+
ty::Bool => Size::from_bytes(1),
926+
ty::Char => Size::from_bytes(4),
927+
ty::Int(ity) => Integer::from_int_ty(&tcx, ity).size(),
928+
ty::Uint(uty) => Integer::from_uint_ty(&tcx, uty).size(),
929+
ty::Float(ty::FloatTy::F32) => Primitive::F32.size(&tcx),
930+
ty::Float(ty::FloatTy::F64) => Primitive::F64.size(&tcx),
931+
_ => bug!("non primitive type"),
932+
}
933+
}
934+
922935
pub fn int_size_and_signed(self, tcx: TyCtxt<'tcx>) -> (Size, bool) {
923-
let (int, signed) = match *self.kind() {
924-
ty::Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
925-
ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
936+
match *self.kind() {
937+
ty::Int(ity) => (Integer::from_int_ty(&tcx, ity).size(), true),
938+
ty::Uint(uty) => (Integer::from_uint_ty(&tcx, uty).size(), false),
926939
_ => bug!("non integer discriminant"),
927-
};
928-
(int.size(), signed)
940+
}
929941
}
930942

931-
/// Returns the maximum value for the given numeric type (including `char`s)
932-
/// or returns `None` if the type is not numeric.
933-
pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
934-
let val = match self.kind() {
943+
/// Returns the minimum and maximum values for the given numeric type (including `char`s) or
944+
/// returns `None` if the type is not numeric.
945+
pub fn numeric_min_and_max_as_bits(self, tcx: TyCtxt<'tcx>) -> Option<(u128, u128)> {
946+
use rustc_apfloat::ieee::{Double, Single};
947+
Some(match self.kind() {
935948
ty::Int(_) | ty::Uint(_) => {
936949
let (size, signed) = self.int_size_and_signed(tcx);
937-
let val =
950+
let min = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 };
951+
let max =
938952
if signed { size.signed_int_max() as u128 } else { size.unsigned_int_max() };
939-
Some(val)
953+
(min, max)
940954
}
941-
ty::Char => Some(std::char::MAX as u128),
942-
ty::Float(fty) => Some(match fty {
943-
ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
944-
ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
945-
}),
946-
_ => None,
947-
};
955+
ty::Char => (0, std::char::MAX as u128),
956+
ty::Float(ty::FloatTy::F32) => {
957+
((-Single::INFINITY).to_bits(), Single::INFINITY.to_bits())
958+
}
959+
ty::Float(ty::FloatTy::F64) => {
960+
((-Double::INFINITY).to_bits(), Double::INFINITY.to_bits())
961+
}
962+
_ => return None,
963+
})
964+
}
948965

949-
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
966+
/// Returns the maximum value for the given numeric type (including `char`s)
967+
/// or returns `None` if the type is not numeric.
968+
pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
969+
self.numeric_min_and_max_as_bits(tcx)
970+
.map(|(_, max)| ty::Const::from_bits(tcx, max, ty::ParamEnv::empty().and(self)))
950971
}
951972

952973
/// Returns the minimum value for the given numeric type (including `char`s)
953974
/// or returns `None` if the type is not numeric.
954975
pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<ty::Const<'tcx>> {
955-
let val = match self.kind() {
956-
ty::Int(_) | ty::Uint(_) => {
957-
let (size, signed) = self.int_size_and_signed(tcx);
958-
let val = if signed { size.truncate(size.signed_int_min() as u128) } else { 0 };
959-
Some(val)
960-
}
961-
ty::Char => Some(0),
962-
ty::Float(fty) => Some(match fty {
963-
ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
964-
ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
965-
}),
966-
_ => None,
967-
};
968-
969-
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
976+
self.numeric_min_and_max_as_bits(tcx)
977+
.map(|(min, _)| ty::Const::from_bits(tcx, min, ty::ParamEnv::empty().and(self)))
970978
}
971979

972980
/// Checks whether values of this type `T` are *moved* or *copied*

‎compiler/rustc_mir_build/src/build/matches/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ enum TestKind<'tcx> {
10351035
ty: Ty<'tcx>,
10361036
},
10371037

1038-
/// Test whether the value falls within an inclusive or exclusive range
1038+
/// Test whether the value falls within an inclusive or exclusive range.
10391039
Range(Box<PatRange<'tcx>>),
10401040

10411041
/// Test that the length of the slice is equal to `len`.

‎compiler/rustc_mir_build/src/build/matches/simplify.rs

+4-40
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@
1515
use crate::build::expr::as_place::PlaceBuilder;
1616
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
1717
use crate::build::Builder;
18-
use rustc_hir::RangeEnd;
1918
use rustc_middle::thir::{self, *};
20-
use rustc_middle::ty;
21-
use rustc_middle::ty::layout::IntegerExt;
22-
use rustc_target::abi::{Integer, Size};
2319

2420
use std::mem;
2521

@@ -148,7 +144,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
148144
match_pair: MatchPair<'pat, 'tcx>,
149145
candidate: &mut Candidate<'pat, 'tcx>,
150146
) -> Result<(), MatchPair<'pat, 'tcx>> {
151-
let tcx = self.tcx;
152147
match match_pair.pattern.kind {
153148
PatKind::AscribeUserType {
154149
ref subpattern,
@@ -210,41 +205,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
210205
Ok(())
211206
}
212207

213-
PatKind::Range(box PatRange { lo, hi, end }) => {
214-
let (range, bias) = match *lo.ty().kind() {
215-
ty::Char => {
216-
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
217-
}
218-
ty::Int(ity) => {
219-
let size = Integer::from_int_ty(&tcx, ity).size();
220-
let max = size.truncate(u128::MAX);
221-
let bias = 1u128 << (size.bits() - 1);
222-
(Some((0, max, size)), bias)
223-
}
224-
ty::Uint(uty) => {
225-
let size = Integer::from_uint_ty(&tcx, uty).size();
226-
let max = size.truncate(u128::MAX);
227-
(Some((0, max, size)), 0)
228-
}
229-
_ => (None, 0),
230-
};
231-
if let Some((min, max, sz)) = range {
232-
// We want to compare ranges numerically, but the order of the bitwise
233-
// representation of signed integers does not match their numeric order. Thus,
234-
// to correct the ordering, we need to shift the range of signed integers to
235-
// correct the comparison. This is achieved by XORing with a bias (see
236-
// pattern/_match.rs for another pertinent example of this pattern).
237-
//
238-
// Also, for performance, it's important to only do the second
239-
// `try_to_bits` if necessary.
240-
let lo = lo.try_to_bits(sz).unwrap() ^ bias;
241-
if lo <= min {
242-
let hi = hi.try_to_bits(sz).unwrap() ^ bias;
243-
if hi > max || hi == max && end == RangeEnd::Included {
244-
// Irrefutable pattern match.
245-
return Ok(());
246-
}
247-
}
208+
PatKind::Range(ref range) => {
209+
if let Some(true) = range.is_full_range(self.tcx) {
210+
// Irrefutable pattern match.
211+
return Ok(());
248212
}
249213
Err(match_pair)
250214
}

‎compiler/rustc_mir_build/src/build/matches/test.rs

+9-38
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use crate::build::expr::as_place::PlaceBuilder;
99
use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
1010
use crate::build::Builder;
11-
use crate::thir::pattern::compare_const_vals;
1211
use rustc_data_structures::fx::FxIndexMap;
1312
use rustc_hir::{LangItem, RangeEnd};
1413
use rustc_index::bit_set::BitSet;
@@ -59,8 +58,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5958
},
6059

6160
PatKind::Range(ref range) => {
62-
assert_eq!(range.lo.ty(), match_pair.pattern.ty);
63-
assert_eq!(range.hi.ty(), match_pair.pattern.ty);
61+
assert_eq!(range.ty, match_pair.pattern.ty);
6462
Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) }
6563
}
6664

@@ -309,11 +307,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
309307
}
310308
}
311309

312-
TestKind::Range(box PatRange { lo, hi, ref end }) => {
310+
TestKind::Range(ref range) => {
313311
let lower_bound_success = self.cfg.start_new_block();
314312
let target_blocks = make_target_blocks(self);
315313

316314
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
315+
// FIXME: skip useless comparison when the range is half-open.
316+
let lo = range.lo.to_const(range.ty, self.tcx);
317+
let hi = range.hi.to_const(range.ty, self.tcx);
317318
let lo = self.literal_operand(test.span, lo);
318319
let hi = self.literal_operand(test.span, hi);
319320
let val = Operand::Copy(place);
@@ -330,7 +331,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
330331
lo,
331332
val.clone(),
332333
);
333-
let op = match *end {
334+
let op = match range.end {
334335
RangeEnd::Included => BinOp::Le,
335336
RangeEnd::Excluded => BinOp::Lt,
336337
};
@@ -698,34 +699,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
698699
}
699700

700701
(TestKind::Range(test), PatKind::Range(pat)) => {
701-
use std::cmp::Ordering::*;
702-
703702
if test == pat {
704703
self.candidate_without_match_pair(match_pair_index, candidate);
705704
return Some(0);
706705
}
707706

708-
// For performance, it's important to only do the second
709-
// `compare_const_vals` if necessary.
710-
let no_overlap = if matches!(
711-
(compare_const_vals(self.tcx, test.hi, pat.lo, self.param_env)?, test.end),
712-
(Less, _) | (Equal, RangeEnd::Excluded) // test < pat
713-
) || matches!(
714-
(compare_const_vals(self.tcx, test.lo, pat.hi, self.param_env)?, pat.end),
715-
(Greater, _) | (Equal, RangeEnd::Excluded) // test > pat
716-
) {
717-
Some(1)
718-
} else {
719-
None
720-
};
721-
722707
// If the testing range does not overlap with pattern range,
723708
// the pattern can be matched only if this test fails.
724-
no_overlap
709+
if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
725710
}
726711

727712
(TestKind::Range(range), &PatKind::Constant { value }) => {
728-
if let Some(false) = self.const_range_contains(&*range, value) {
713+
if !range.contains(value, self.tcx, self.param_env)? {
729714
// `value` is not contained in the testing range,
730715
// so `value` can be matched only if this test fails.
731716
Some(1)
@@ -817,27 +802,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
817802
span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
818803
}
819804

820-
fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option<bool> {
821-
use std::cmp::Ordering::*;
822-
823-
// For performance, it's important to only do the second
824-
// `compare_const_vals` if necessary.
825-
Some(
826-
matches!(compare_const_vals(self.tcx, range.lo, value, self.param_env)?, Less | Equal)
827-
&& matches!(
828-
(compare_const_vals(self.tcx, value, range.hi, self.param_env)?, range.end),
829-
(Less, _) | (Equal, RangeEnd::Included)
830-
),
831-
)
832-
}
833-
834805
fn values_not_contained_in_range(
835806
&self,
836807
range: &PatRange<'tcx>,
837808
options: &FxIndexMap<Const<'tcx>, u128>,
838809
) -> Option<bool> {
839810
for &val in options.keys() {
840-
if self.const_range_contains(range, val)? {
811+
if range.contains(val, self.tcx, self.param_env)? {
841812
return Some(false);
842813
}
843814
}

‎compiler/rustc_mir_build/src/errors.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -807,13 +807,19 @@ impl<'tcx> Uncovered<'tcx> {
807807
cx: &MatchCheckCtxt<'p, 'tcx>,
808808
witnesses: Vec<WitnessPat<'tcx>>,
809809
) -> Self {
810-
let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
810+
let witness_1 = witnesses.get(0).unwrap().to_diagnostic_pat(cx);
811811
Self {
812812
span,
813813
count: witnesses.len(),
814814
// Substitute dummy values if witnesses is smaller than 3. These will never be read.
815-
witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
816-
witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
815+
witness_2: witnesses
816+
.get(1)
817+
.map(|w| w.to_diagnostic_pat(cx))
818+
.unwrap_or_else(|| witness_1.clone()),
819+
witness_3: witnesses
820+
.get(2)
821+
.map(|w| w.to_diagnostic_pat(cx))
822+
.unwrap_or_else(|| witness_1.clone()),
817823
witness_1,
818824
remainder: witnesses.len().saturating_sub(3),
819825
}

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

+25-10
Original file line numberDiff line numberDiff line change
@@ -703,14 +703,21 @@ fn report_arm_reachability<'p, 'tcx>(
703703
}
704704

705705
fn collect_non_exhaustive_tys<'tcx>(
706+
tcx: TyCtxt<'tcx>,
706707
pat: &WitnessPat<'tcx>,
707708
non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
708709
) {
709710
if matches!(pat.ctor(), Constructor::NonExhaustive) {
710711
non_exhaustive_tys.insert(pat.ty());
711712
}
713+
if let Constructor::IntRange(range) = pat.ctor() {
714+
if range.is_beyond_boundaries(pat.ty(), tcx) {
715+
// The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`.
716+
non_exhaustive_tys.insert(pat.ty());
717+
}
718+
}
712719
pat.iter_fields()
713-
.for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
720+
.for_each(|field_pat| collect_non_exhaustive_tys(tcx, field_pat, non_exhaustive_tys))
714721
}
715722

716723
/// Report that a match is not exhaustive.
@@ -753,7 +760,7 @@ fn non_exhaustive_match<'p, 'tcx>(
753760
pattern = if witnesses.len() < 4 {
754761
witnesses
755762
.iter()
756-
.map(|witness| witness.to_pat(cx).to_string())
763+
.map(|witness| witness.to_diagnostic_pat(cx).to_string())
757764
.collect::<Vec<String>>()
758765
.join(" | ")
759766
} else {
@@ -764,16 +771,24 @@ fn non_exhaustive_match<'p, 'tcx>(
764771
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
765772
err.note(format!("the matched value is of type `{}`", scrut_ty));
766773

767-
if !is_empty_match && witnesses.len() == 1 {
774+
if !is_empty_match {
768775
let mut non_exhaustive_tys = FxHashSet::default();
769-
collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
776+
// Look at the first witness.
777+
collect_non_exhaustive_tys(cx.tcx, &witnesses[0], &mut non_exhaustive_tys);
770778

771779
for ty in non_exhaustive_tys {
772780
if ty.is_ptr_sized_integral() {
773-
err.note(format!(
774-
"`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
775-
exhaustively",
781+
if ty == cx.tcx.types.usize {
782+
err.note(format!(
783+
"`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \
784+
exhaustively",
776785
));
786+
} else if ty == cx.tcx.types.isize {
787+
err.note(format!(
788+
"`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \
789+
exhaustively",
790+
));
791+
}
777792
if cx.tcx.sess.is_nightly_build() {
778793
err.help(format!(
779794
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
@@ -900,13 +915,13 @@ pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
900915
witnesses: &[WitnessPat<'tcx>],
901916
) -> String {
902917
const LIMIT: usize = 3;
903-
let pat_to_str = |pat: &WitnessPat<'tcx>| pat.to_pat(cx).to_string();
918+
let pat_to_str = |pat: &WitnessPat<'tcx>| pat.to_diagnostic_pat(cx).to_string();
904919
match witnesses {
905920
[] => bug!(),
906-
[witness] => format!("`{}`", witness.to_pat(cx)),
921+
[witness] => format!("`{}`", witness.to_diagnostic_pat(cx)),
907922
[head @ .., tail] if head.len() < LIMIT => {
908923
let head: Vec<_> = head.iter().map(pat_to_str).collect();
909-
format!("`{}` and `{}`", head.join("`, `"), tail.to_pat(cx))
924+
format!("`{}` and `{}`", head.join("`, `"), tail.to_diagnostic_pat(cx))
910925
}
911926
_ => {
912927
let (head, tail) = witnesses.split_at(LIMIT);

‎compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+317-164
Large diffs are not rendered by default.

‎compiler/rustc_mir_build/src/thir/pattern/mod.rs

+24-87
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
1717
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
1818
use rustc_hir::RangeEnd;
1919
use rustc_index::Idx;
20-
use rustc_middle::mir::interpret::{
21-
ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
22-
};
20+
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
2321
use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection};
24-
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
22+
use rustc_middle::thir::{
23+
Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
24+
};
2525
use rustc_middle::ty::layout::IntegerExt;
2626
use rustc_middle::ty::{
2727
self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt,
@@ -90,7 +90,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
9090
&mut self,
9191
expr: Option<&'tcx hir::Expr<'tcx>>,
9292
) -> Result<
93-
(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
93+
(Option<PatRangeBoundary<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
9494
ErrorGuaranteed,
9595
> {
9696
match expr {
@@ -113,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
113113
);
114114
return Err(self.tcx.sess.delay_span_bug(expr.span, msg));
115115
};
116-
Ok((Some(value), ascr, inline_const))
116+
Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
117117
}
118118
}
119119
}
@@ -187,32 +187,25 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
187187
let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
188188
let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
189189

190-
let lo = lo.unwrap_or_else(|| {
191-
// Unwrap is ok because the type is known to be numeric.
192-
let lo = ty.numeric_min_val(self.tcx).unwrap();
193-
mir::Const::from_ty_const(lo, self.tcx)
194-
});
195-
let hi = hi.unwrap_or_else(|| {
196-
// Unwrap is ok because the type is known to be numeric.
197-
let hi = ty.numeric_max_val(self.tcx).unwrap();
198-
mir::Const::from_ty_const(hi, self.tcx)
199-
});
200-
assert_eq!(lo.ty(), ty);
201-
assert_eq!(hi.ty(), ty);
202-
203-
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env);
204-
let mut kind = match (end, cmp) {
190+
let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
191+
let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);
192+
193+
let cmp = lo.compare_with(hi, ty, self.tcx, self.param_env);
194+
let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
195+
match (end, cmp) {
205196
// `x..y` where `x < y`.
206-
// Non-empty because the range includes at least `x`.
207-
(RangeEnd::Excluded, Some(Ordering::Less)) => {
208-
PatKind::Range(Box::new(PatRange { lo, hi, end }))
209-
}
210-
// `x..=y` where `x == y`.
211-
(RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
197+
(RangeEnd::Excluded, Some(Ordering::Less)) => {}
212198
// `x..=y` where `x < y`.
213-
(RangeEnd::Included, Some(Ordering::Less)) => {
214-
PatKind::Range(Box::new(PatRange { lo, hi, end }))
215-
}
199+
(RangeEnd::Included, Some(Ordering::Less)) => {}
200+
// `x..=y` where `x == y` and `x` and `y` are finite.
201+
(RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
202+
kind = PatKind::Constant { value: lo.as_finite().unwrap() };
203+
}
204+
// `..=x` where `x == ty::MIN`.
205+
(RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}
206+
// `x..` where `x == ty::MAX` (yes, `x..` gives `RangeEnd::Included` since it is meant
207+
// to include `ty::MAX`).
208+
(RangeEnd::Included, Some(Ordering::Equal)) if !hi.is_finite() => {}
216209
// `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error.
217210
_ => {
218211
// Emit a more appropriate message if there was overflow.
@@ -231,7 +224,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
231224
};
232225
return Err(e);
233226
}
234-
};
227+
}
235228

236229
// If we are handling a range with associated constants (e.g.
237230
// `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
@@ -851,59 +844,3 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
851844
}
852845
}
853846
}
854-
855-
#[instrument(skip(tcx), level = "debug")]
856-
pub(crate) fn compare_const_vals<'tcx>(
857-
tcx: TyCtxt<'tcx>,
858-
a: mir::Const<'tcx>,
859-
b: mir::Const<'tcx>,
860-
param_env: ty::ParamEnv<'tcx>,
861-
) -> Option<Ordering> {
862-
assert_eq!(a.ty(), b.ty());
863-
864-
let ty = a.ty();
865-
866-
// This code is hot when compiling matches with many ranges. So we
867-
// special-case extraction of evaluated scalars for speed, for types where
868-
// raw data comparisons are appropriate. E.g. `unicode-normalization` has
869-
// many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
870-
// in this way.
871-
match ty.kind() {
872-
ty::Float(_) | ty::Int(_) => {} // require special handling, see below
873-
_ => match (a, b) {
874-
(
875-
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
876-
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
877-
) => return Some(a.cmp(&b)),
878-
(mir::Const::Ty(a), mir::Const::Ty(b)) => {
879-
return Some(a.kind().cmp(&b.kind()));
880-
}
881-
_ => {}
882-
},
883-
}
884-
885-
let a = a.eval_bits(tcx, param_env);
886-
let b = b.eval_bits(tcx, param_env);
887-
888-
use rustc_apfloat::Float;
889-
match *ty.kind() {
890-
ty::Float(ty::FloatTy::F32) => {
891-
let a = rustc_apfloat::ieee::Single::from_bits(a);
892-
let b = rustc_apfloat::ieee::Single::from_bits(b);
893-
a.partial_cmp(&b)
894-
}
895-
ty::Float(ty::FloatTy::F64) => {
896-
let a = rustc_apfloat::ieee::Double::from_bits(a);
897-
let b = rustc_apfloat::ieee::Double::from_bits(b);
898-
a.partial_cmp(&b)
899-
}
900-
ty::Int(ity) => {
901-
use rustc_middle::ty::layout::IntegerExt;
902-
let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size();
903-
let a = size.sign_extend(a);
904-
let b = size.sign_extend(b);
905-
Some((a as i128).cmp(&(b as i128)))
906-
}
907-
_ => Some(a.cmp(&b)),
908-
}
909-
}

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

+12-11
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@
308308
use self::ArmType::*;
309309
use self::Usefulness::*;
310310
use super::deconstruct_pat::{
311-
Constructor, ConstructorSet, DeconstructedPat, IntRange, SplitConstructorSet, WitnessPat,
311+
Constructor, ConstructorSet, DeconstructedPat, IntRange, MaybeInfiniteInt, SplitConstructorSet,
312+
WitnessPat,
312313
};
313314
use crate::errors::{NonExhaustiveOmittedPattern, Overlap, OverlappingRangeEndpoints, Uncovered};
314315

@@ -1013,7 +1014,7 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
10131014

10141015
if IntRange::is_integral(ty) {
10151016
let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
1016-
let overlap_as_pat = overlap.to_pat(cx.tcx, ty);
1017+
let overlap_as_pat = overlap.to_diagnostic_pat(ty, cx.tcx);
10171018
let overlaps: Vec<_> = overlapped_spans
10181019
.iter()
10191020
.copied()
@@ -1031,9 +1032,10 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
10311032
let split_int_ranges = set.present.iter().filter_map(|c| c.as_int_range());
10321033
for overlap_range in split_int_ranges.clone() {
10331034
if overlap_range.is_singleton() {
1034-
let overlap: u128 = overlap_range.boundaries().0;
1035-
// Spans of ranges that start or end with the overlap.
1035+
let overlap: MaybeInfiniteInt = overlap_range.lo;
1036+
// Ranges that look like `lo..=overlap`.
10361037
let mut prefixes: SmallVec<[_; 1]> = Default::default();
1038+
// Ranges that look like `overlap..=hi`.
10371039
let mut suffixes: SmallVec<[_; 1]> = Default::default();
10381040
// Iterate on patterns that contained `overlap`.
10391041
for pat in column.iter() {
@@ -1043,17 +1045,16 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>(
10431045
// Don't lint when one of the ranges is a singleton.
10441046
continue;
10451047
}
1046-
let (start, end) = this_range.boundaries();
1047-
if start == overlap {
1048-
// `this_range` looks like `overlap..=end`; it overlaps with any ranges that
1049-
// look like `start..=overlap`.
1048+
if this_range.lo == overlap {
1049+
// `this_range` looks like `overlap..=this_range.hi`; it overlaps with any
1050+
// ranges that look like `lo..=overlap`.
10501051
if !prefixes.is_empty() {
10511052
emit_lint(overlap_range, this_span, &prefixes);
10521053
}
10531054
suffixes.push(this_span)
1054-
} else if end == overlap {
1055-
// `this_range` looks like `start..=overlap`; it overlaps with any ranges
1056-
// that look like `overlap..=end`.
1055+
} else if this_range.hi == overlap.plus_one() {
1056+
// `this_range` looks like `this_range.lo..=overlap`; it overlaps with any
1057+
// ranges that look like `overlap..=hi`.
10571058
if !suffixes.is_empty() {
10581059
emit_lint(overlap_range, this_span, &suffixes);
10591060
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
fn main() {
22
match 0usize {
3-
//~^ ERROR non-exhaustive patterns: `_` not covered
4-
//~| NOTE pattern `_` not covered
3+
//~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered
4+
//~| NOTE pattern `usize::MAX..` not covered
55
//~| NOTE the matched value is of type `usize`
66
//~| NOTE `usize` does not have a fixed maximum value
77
0..=usize::MAX => {}
88
}
99

1010
match 0isize {
11-
//~^ ERROR non-exhaustive patterns: `_` not covered
12-
//~| NOTE pattern `_` not covered
11+
//~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
12+
//~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered
1313
//~| NOTE the matched value is of type `isize`
14-
//~| NOTE `isize` does not have a fixed maximum value
14+
//~| NOTE `isize` does not have fixed minimum and maximum values
1515
isize::MIN..=isize::MAX => {}
1616
}
1717
}

‎tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
error[E0004]: non-exhaustive patterns: `_` not covered
1+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
22
--> $DIR/feature-gate-precise_pointer_size_matching.rs:2:11
33
|
44
LL | match 0usize {
5-
| ^^^^^^ pattern `_` not covered
5+
| ^^^^^^ pattern `usize::MAX..` not covered
66
|
77
= note: the matched value is of type `usize`
8-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
8+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
99
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
1010
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1111
|
1212
LL ~ 0..=usize::MAX => {},
13-
LL + _ => todo!()
13+
LL + usize::MAX.. => todo!()
1414
|
1515

16-
error[E0004]: non-exhaustive patterns: `_` not covered
16+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
1717
--> $DIR/feature-gate-precise_pointer_size_matching.rs:10:11
1818
|
1919
LL | match 0isize {
20-
| ^^^^^^ pattern `_` not covered
20+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
2121
|
2222
= note: the matched value is of type `isize`
23-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
23+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
2424
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
25-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
25+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
2626
|
2727
LL ~ isize::MIN..=isize::MAX => {},
28-
LL + _ => todo!()
28+
LL + ..isize::MIN | isize::MAX.. => todo!()
2929
|
3030

3131
error: aborting due to 2 previous errors

‎tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
2-
--> $DIR/pointer-sized-int.rs:48:11
2+
--> $DIR/pointer-sized-int.rs:54:11
33
|
44
LL | match 7usize {}
55
| ^^^^^^

‎tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr

+70-70
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,162 @@
1-
error[E0004]: non-exhaustive patterns: `_` not covered
2-
--> $DIR/pointer-sized-int.rs:12:11
1+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
2+
--> $DIR/pointer-sized-int.rs:14:11
33
|
44
LL | match 0usize {
5-
| ^^^^^^ pattern `_` not covered
5+
| ^^^^^^ pattern `usize::MAX..` not covered
66
|
77
= note: the matched value is of type `usize`
8-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
8+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
99
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
1010
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1111
|
1212
LL ~ 0 ..= usize::MAX => {},
13-
LL + _ => todo!()
13+
LL + usize::MAX.. => todo!()
1414
|
1515

16-
error[E0004]: non-exhaustive patterns: `_` not covered
17-
--> $DIR/pointer-sized-int.rs:17:11
16+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
17+
--> $DIR/pointer-sized-int.rs:19:11
1818
|
1919
LL | match 0isize {
20-
| ^^^^^^ pattern `_` not covered
20+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
2121
|
2222
= note: the matched value is of type `isize`
23-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
23+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
2424
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
25-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
25+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
2626
|
2727
LL ~ isize::MIN ..= isize::MAX => {},
28-
LL + _ => todo!()
28+
LL + ..isize::MIN | isize::MAX.. => todo!()
2929
|
3030

31-
error[E0004]: non-exhaustive patterns: `_` not covered
32-
--> $DIR/pointer-sized-int.rs:22:8
31+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
32+
--> $DIR/pointer-sized-int.rs:25:8
3333
|
3434
LL | m!(0usize, 0..=usize::MAX);
35-
| ^^^^^^ pattern `_` not covered
35+
| ^^^^^^ pattern `usize::MAX..` not covered
3636
|
3737
= note: the matched value is of type `usize`
38-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
38+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
3939
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
4040
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
4141
|
42-
LL | match $s { $($t)+ => {}, _ => todo!() }
43-
| ++++++++++++++
42+
LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
43+
| +++++++++++++++++++++++++
4444

45-
error[E0004]: non-exhaustive patterns: `_` not covered
46-
--> $DIR/pointer-sized-int.rs:24:8
45+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
46+
--> $DIR/pointer-sized-int.rs:27:8
4747
|
4848
LL | m!(0usize, 0..5 | 5..=usize::MAX);
49-
| ^^^^^^ pattern `_` not covered
49+
| ^^^^^^ pattern `usize::MAX..` not covered
5050
|
5151
= note: the matched value is of type `usize`
52-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
52+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
5353
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
5454
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
5555
|
56-
LL | match $s { $($t)+ => {}, _ => todo!() }
57-
| ++++++++++++++
56+
LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
57+
| +++++++++++++++++++++++++
5858

59-
error[E0004]: non-exhaustive patterns: `_` not covered
60-
--> $DIR/pointer-sized-int.rs:26:8
59+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
60+
--> $DIR/pointer-sized-int.rs:29:8
6161
|
6262
LL | m!(0usize, 0..usize::MAX | usize::MAX);
63-
| ^^^^^^ pattern `_` not covered
63+
| ^^^^^^ pattern `usize::MAX..` not covered
6464
|
6565
= note: the matched value is of type `usize`
66-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
66+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
6767
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
6868
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
6969
|
70-
LL | match $s { $($t)+ => {}, _ => todo!() }
71-
| ++++++++++++++
70+
LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() }
71+
| +++++++++++++++++++++++++
7272

73-
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
74-
--> $DIR/pointer-sized-int.rs:28:8
73+
error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
74+
--> $DIR/pointer-sized-int.rs:31:8
7575
|
7676
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
77-
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
77+
| ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
7878
|
7979
= note: the matched value is of type `(usize, bool)`
80-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
80+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
8181
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
8282
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
8383
|
84-
LL | match $s { $($t)+ => {}, (_, _) => todo!() }
85-
| +++++++++++++++++++
84+
LL | match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() }
85+
| ++++++++++++++++++++++++++++++
8686

87-
error[E0004]: non-exhaustive patterns: `_` not covered
88-
--> $DIR/pointer-sized-int.rs:31:8
87+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
88+
--> $DIR/pointer-sized-int.rs:36:8
8989
|
9090
LL | m!(0isize, isize::MIN..=isize::MAX);
91-
| ^^^^^^ pattern `_` not covered
91+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
9292
|
9393
= note: the matched value is of type `isize`
94-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
94+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
9595
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
96-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
96+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
9797
|
98-
LL | match $s { $($t)+ => {}, _ => todo!() }
99-
| ++++++++++++++
98+
LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
99+
| ++++++++++++++++++++++++++++++++++++++++
100100

101-
error[E0004]: non-exhaustive patterns: `_` not covered
102-
--> $DIR/pointer-sized-int.rs:33:8
101+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
102+
--> $DIR/pointer-sized-int.rs:38:8
103103
|
104104
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
105-
| ^^^^^^ pattern `_` not covered
105+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
106106
|
107107
= note: the matched value is of type `isize`
108-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
108+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
109109
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
110-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
110+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
111111
|
112-
LL | match $s { $($t)+ => {}, _ => todo!() }
113-
| ++++++++++++++
112+
LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
113+
| ++++++++++++++++++++++++++++++++++++++++
114114

115-
error[E0004]: non-exhaustive patterns: `_` not covered
116-
--> $DIR/pointer-sized-int.rs:35:8
115+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
116+
--> $DIR/pointer-sized-int.rs:40:8
117117
|
118118
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
119-
| ^^^^^^ pattern `_` not covered
119+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
120120
|
121121
= note: the matched value is of type `isize`
122-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
122+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
123123
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
124-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
124+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
125125
|
126-
LL | match $s { $($t)+ => {}, _ => todo!() }
127-
| ++++++++++++++
126+
LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() }
127+
| ++++++++++++++++++++++++++++++++++++++++
128128

129-
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
130-
--> $DIR/pointer-sized-int.rs:37:8
129+
error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
130+
--> $DIR/pointer-sized-int.rs:42:8
131131
|
132132
LL | m!((0isize, true), (isize::MIN..5, true)
133-
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
133+
| ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
134134
|
135135
= note: the matched value is of type `(isize, bool)`
136-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
136+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
137137
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
138-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
138+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
139139
|
140-
LL | match $s { $($t)+ => {}, (_, _) => todo!() }
141-
| +++++++++++++++++++
140+
LL | match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() }
141+
| ++++++++++++++++++++++++++++++++++++++++++++++++++
142142

143-
error[E0004]: non-exhaustive patterns: `_` not covered
144-
--> $DIR/pointer-sized-int.rs:41:11
143+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
144+
--> $DIR/pointer-sized-int.rs:47:11
145145
|
146146
LL | match 0isize {
147-
| ^^^^^^ pattern `_` not covered
147+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
148148
|
149149
= note: the matched value is of type `isize`
150-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
150+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
151151
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
152-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
152+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
153153
|
154154
LL ~ 1 ..= isize::MAX => {},
155-
LL + _ => todo!()
155+
LL + ..isize::MIN | isize::MAX.. => todo!()
156156
|
157157

158158
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
159-
--> $DIR/pointer-sized-int.rs:48:11
159+
--> $DIR/pointer-sized-int.rs:54:11
160160
|
161161
LL | match 7usize {}
162162
| ^^^^^^

‎tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// revisions: allow deny
22
#![feature(exclusive_range_pattern)]
33
#![cfg_attr(allow, feature(precise_pointer_size_matching))]
4+
#![allow(overlapping_range_endpoints)]
45

56
macro_rules! m {
67
($s:expr, $($t:tt)+) => {
78
match $s { $($t)+ => {} }
89
}
910
}
1011

12+
#[rustfmt::skip]
1113
fn main() {
1214
match 0usize {
1315
//[deny]~^ ERROR non-exhaustive patterns
@@ -19,6 +21,7 @@ fn main() {
1921
isize::MIN ..= isize::MAX => {}
2022
}
2123

24+
m!(0usize, 0..);
2225
m!(0usize, 0..=usize::MAX);
2326
//[deny]~^ ERROR non-exhaustive patterns
2427
m!(0usize, 0..5 | 5..=usize::MAX);
@@ -27,7 +30,9 @@ fn main() {
2730
//[deny]~^ ERROR non-exhaustive patterns
2831
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
2932
//[deny]~^ ERROR non-exhaustive patterns
33+
m!(0usize, 0..=usize::MAX | usize::MAX..);
3034

35+
m!(0isize, ..0 | 0..);
3136
m!(0isize, isize::MIN..=isize::MAX);
3237
//[deny]~^ ERROR non-exhaustive patterns
3338
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
@@ -37,6 +42,7 @@ fn main() {
3742
m!((0isize, true), (isize::MIN..5, true)
3843
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
3944
//[deny]~^^ ERROR non-exhaustive patterns
45+
m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..);
4046

4147
match 0isize {
4248
//[deny]~^ ERROR non-exhaustive patterns
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// This tests that the lint message explains the reason for the error.
22
fn main() {
33
match 0usize {
4-
//~^ ERROR non-exhaustive patterns: `_` not covered
5-
//~| NOTE pattern `_` not covered
4+
//~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered
5+
//~| NOTE pattern `usize::MAX..` not covered
66
//~| NOTE the matched value is of type `usize`
77
//~| NOTE `usize` does not have a fixed maximum value
88
0..=usize::MAX => {}
99
}
1010

1111
match 0isize {
12-
//~^ ERROR non-exhaustive patterns: `_` not covered
13-
//~| NOTE pattern `_` not covered
12+
//~^ ERROR non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
13+
//~| NOTE patterns `..isize::MIN` and `isize::MAX..` not covered
1414
//~| NOTE the matched value is of type `isize`
15-
//~| NOTE `isize` does not have a fixed maximum value
15+
//~| NOTE `isize` does not have fixed minimum and maximum values
1616
isize::MIN..=isize::MAX => {}
1717
}
1818
}

‎tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
1-
error[E0004]: non-exhaustive patterns: `_` not covered
1+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
22
--> $DIR/precise_pointer_matching-message.rs:3:11
33
|
44
LL | match 0usize {
5-
| ^^^^^^ pattern `_` not covered
5+
| ^^^^^^ pattern `usize::MAX..` not covered
66
|
77
= note: the matched value is of type `usize`
8-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
8+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
99
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
1010
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1111
|
1212
LL ~ 0..=usize::MAX => {},
13-
LL + _ => todo!()
13+
LL + usize::MAX.. => todo!()
1414
|
1515

16-
error[E0004]: non-exhaustive patterns: `_` not covered
16+
error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered
1717
--> $DIR/precise_pointer_matching-message.rs:11:11
1818
|
1919
LL | match 0isize {
20-
| ^^^^^^ pattern `_` not covered
20+
| ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered
2121
|
2222
= note: the matched value is of type `isize`
23-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
23+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
2424
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
25-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
25+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
2626
|
2727
LL ~ isize::MIN..=isize::MAX => {},
28-
LL + _ => todo!()
28+
LL + ..isize::MIN | isize::MAX.. => todo!()
2929
|
3030

3131
error: aborting due to 2 previous errors

‎tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ struct B<T, U>(T, U);
66

77
fn main() {
88
match 0 {
9-
//~^ ERROR non-exhaustive patterns: `_` not covered [E0004]
9+
//~^ ERROR non-exhaustive patterns: `usize::MAX..` not covered [E0004]
1010
0 => (),
1111
1..=usize::MAX => (),
1212
}
1313

1414
match (0usize, 0usize) {
15-
//~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
15+
//~^ ERROR non-exhaustive patterns: `(usize::MAX.., _)` not covered [E0004]
1616
(0, 0) => (),
1717
(1..=usize::MAX, 1..=usize::MAX) => (),
1818
}
1919

2020
match (0isize, 0usize) {
21-
//~^ ERROR non-exhaustive patterns: `(_, _)` not covered [E0004]
21+
//~^ ERROR non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered [E0004]
2222
(isize::MIN..=isize::MAX, 0) => (),
2323
(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
2424
}
@@ -30,14 +30,14 @@ fn main() {
3030
}
3131

3232
match Some(4) {
33-
//~^ ERROR non-exhaustive patterns: `Some(_)` not covered
33+
//~^ ERROR non-exhaustive patterns: `Some(usize::MAX..)` not covered
3434
Some(0) => (),
3535
Some(1..=usize::MAX) => (),
3636
None => (),
3737
}
3838

3939
match Some(Some(Some(0))) {
40-
//~^ ERROR non-exhaustive patterns: `Some(Some(Some(_)))` not covered
40+
//~^ ERROR non-exhaustive patterns: `Some(Some(Some(usize::MAX..)))` not covered
4141
Some(Some(Some(0))) => (),
4242
Some(Some(Some(1..=usize::MAX))) => (),
4343
Some(Some(None)) => (),
@@ -46,21 +46,21 @@ fn main() {
4646
}
4747

4848
match (A { a: 0usize }) {
49-
//~^ ERROR non-exhaustive patterns: `A { .. }` not covered [E0004]
49+
//~^ ERROR non-exhaustive patterns: `A { a: usize::MAX.. }` not covered [E0004]
5050
A { a: 0 } => (),
5151
A { a: 1..=usize::MAX } => (),
5252
}
5353

5454
match B(0isize, 0usize) {
55-
//~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
55+
//~^ ERROR non-exhaustive patterns: `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered [E0004]
5656
B(isize::MIN..=isize::MAX, 0) => (),
5757
B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
5858
}
5959

6060
// Should report only the note about usize not having fixed max value and not report
6161
// report the note about isize
6262
match B(0isize, 0usize) {
63-
//~^ ERROR non-exhaustive patterns: `B(_, _)` not covered [E0004]
63+
//~^ ERROR non-exhaustive patterns: `B(_, usize::MAX..)` not covered [E0004]
6464
B(_, 0) => (),
6565
B(_, 1..=usize::MAX) => (),
6666
}

‎tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr

+34-34
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1-
error[E0004]: non-exhaustive patterns: `_` not covered
1+
error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered
22
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:8:11
33
|
44
LL | match 0 {
5-
| ^ pattern `_` not covered
5+
| ^ pattern `usize::MAX..` not covered
66
|
77
= note: the matched value is of type `usize`
8-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
8+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
99
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
1010
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
1111
|
1212
LL ~ 1..=usize::MAX => (),
13-
LL ~ _ => todo!(),
13+
LL ~ usize::MAX.. => todo!(),
1414
|
1515

16-
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
16+
error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered
1717
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:14:11
1818
|
1919
LL | match (0usize, 0usize) {
20-
| ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
20+
| ^^^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered
2121
|
2222
= note: the matched value is of type `(usize, usize)`
23-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
23+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
2424
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
2525
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
2626
|
2727
LL ~ (1..=usize::MAX, 1..=usize::MAX) => (),
28-
LL ~ (_, _) => todo!(),
28+
LL ~ (usize::MAX.., _) => todo!(),
2929
|
3030

31-
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
31+
error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
3232
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:20:11
3333
|
3434
LL | match (0isize, 0usize) {
35-
| ^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
35+
| ^^^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered
3636
|
3737
= note: the matched value is of type `(isize, usize)`
38-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
38+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
3939
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
40-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
40+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
4141
|
4242
LL ~ (isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
43-
LL ~ (_, _) => todo!(),
43+
LL ~ (..isize::MIN, _) | (isize::MAX.., _) => todo!(),
4444
|
4545

4646
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
@@ -61,31 +61,31 @@ LL ~ None => {},
6161
LL + Some(_) => todo!()
6262
|
6363

64-
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
64+
error[E0004]: non-exhaustive patterns: `Some(usize::MAX..)` not covered
6565
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:32:11
6666
|
6767
LL | match Some(4) {
68-
| ^^^^^^^ pattern `Some(_)` not covered
68+
| ^^^^^^^ pattern `Some(usize::MAX..)` not covered
6969
|
7070
note: `Option<usize>` defined here
7171
--> $SRC_DIR/core/src/option.rs:LL:COL
7272
::: $SRC_DIR/core/src/option.rs:LL:COL
7373
|
7474
= note: not covered
7575
= note: the matched value is of type `Option<usize>`
76-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
76+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
7777
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
7878
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
7979
|
8080
LL ~ None => (),
81-
LL ~ Some(_) => todo!(),
81+
LL ~ Some(usize::MAX..) => todo!(),
8282
|
8383

84-
error[E0004]: non-exhaustive patterns: `Some(Some(Some(_)))` not covered
84+
error[E0004]: non-exhaustive patterns: `Some(Some(Some(usize::MAX..)))` not covered
8585
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:39:11
8686
|
8787
LL | match Some(Some(Some(0))) {
88-
| ^^^^^^^^^^^^^^^^^^^ pattern `Some(Some(Some(_)))` not covered
88+
| ^^^^^^^^^^^^^^^^^^^ pattern `Some(Some(Some(usize::MAX..)))` not covered
8989
|
9090
note: `Option<Option<Option<usize>>>` defined here
9191
--> $SRC_DIR/core/src/option.rs:LL:COL
@@ -97,72 +97,72 @@ note: `Option<Option<Option<usize>>>` defined here
9797
|
9898
= note: not covered
9999
= note: the matched value is of type `Option<Option<Option<usize>>>`
100-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
100+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
101101
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
102102
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
103103
|
104104
LL ~ None => (),
105-
LL ~ Some(Some(Some(_))) => todo!(),
105+
LL ~ Some(Some(Some(usize::MAX..))) => todo!(),
106106
|
107107

108-
error[E0004]: non-exhaustive patterns: `A { .. }` not covered
108+
error[E0004]: non-exhaustive patterns: `A { a: usize::MAX.. }` not covered
109109
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:48:11
110110
|
111111
LL | match (A { a: 0usize }) {
112-
| ^^^^^^^^^^^^^^^^^ pattern `A { .. }` not covered
112+
| ^^^^^^^^^^^^^^^^^ pattern `A { a: usize::MAX.. }` not covered
113113
|
114114
note: `A<usize>` defined here
115115
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:1:8
116116
|
117117
LL | struct A<T> {
118118
| ^
119119
= note: the matched value is of type `A<usize>`
120-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
120+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
121121
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
122122
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
123123
|
124124
LL ~ A { a: 1..=usize::MAX } => (),
125-
LL ~ A { .. } => todo!(),
125+
LL ~ A { a: usize::MAX.. } => todo!(),
126126
|
127127

128-
error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
128+
error[E0004]: non-exhaustive patterns: `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered
129129
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:54:11
130130
|
131131
LL | match B(0isize, 0usize) {
132-
| ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
132+
| ^^^^^^^^^^^^^^^^^ patterns `B(..isize::MIN, _)` and `B(isize::MAX.., _)` not covered
133133
|
134134
note: `B<isize, usize>` defined here
135135
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
136136
|
137137
LL | struct B<T, U>(T, U);
138138
| ^
139139
= note: the matched value is of type `B<isize, usize>`
140-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
140+
= note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively
141141
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
142-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
142+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
143143
|
144144
LL ~ B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (),
145-
LL ~ B(_, _) => todo!(),
145+
LL ~ B(..isize::MIN, _) | B(isize::MAX.., _) => todo!(),
146146
|
147147

148-
error[E0004]: non-exhaustive patterns: `B(_, _)` not covered
148+
error[E0004]: non-exhaustive patterns: `B(_, usize::MAX..)` not covered
149149
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:62:11
150150
|
151151
LL | match B(0isize, 0usize) {
152-
| ^^^^^^^^^^^^^^^^^ pattern `B(_, _)` not covered
152+
| ^^^^^^^^^^^^^^^^^ pattern `B(_, usize::MAX..)` not covered
153153
|
154154
note: `B<isize, usize>` defined here
155155
--> $DIR/issue-85222-types-containing-non-exhaustive-types.rs:5:8
156156
|
157157
LL | struct B<T, U>(T, U);
158158
| ^
159159
= note: the matched value is of type `B<isize, usize>`
160-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
160+
= note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively
161161
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
162162
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
163163
|
164164
LL ~ B(_, 1..=usize::MAX) => (),
165-
LL ~ B(_, _) => todo!(),
165+
LL ~ B(_, usize::MAX..) => todo!(),
166166
|
167167

168168
error: aborting due to 9 previous errors

‎tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs

+33-20
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,101 @@
11
struct Foo {
22
first: bool,
3-
second: Option<[usize; 4]>
3+
second: Option<[usize; 4]>,
44
}
55

66
fn struct_with_a_nested_enum_and_vector() {
77
match (Foo { first: true, second: None }) {
8-
//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
8+
//~^ ERROR non-exhaustive patterns: `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
99
Foo { first: true, second: None } => (),
1010
Foo { first: true, second: Some(_) } => (),
1111
Foo { first: false, second: None } => (),
12-
Foo { first: false, second: Some([1, 2, 3, 4]) } => ()
12+
Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
1313
}
1414
}
1515

1616
enum Color {
1717
Red,
1818
Green,
19-
CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
19+
CustomRGBA { a: bool, r: u8, g: u8, b: u8 },
2020
}
2121

2222
fn enum_with_single_missing_variant() {
2323
match Color::Red {
24-
//~^ ERROR non-exhaustive patterns: `Color::Red` not covered
24+
//~^ ERROR non-exhaustive patterns: `Color::Red` not covered
2525
Color::CustomRGBA { .. } => (),
26-
Color::Green => ()
26+
Color::Green => (),
2727
}
2828
}
2929

3030
enum Direction {
31-
North, East, South, West
31+
North,
32+
East,
33+
South,
34+
West,
3235
}
3336

3437
fn enum_with_multiple_missing_variants() {
3538
match Direction::North {
36-
//~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
37-
Direction::North => ()
39+
//~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
40+
Direction::North => (),
3841
}
3942
}
4043

4144
enum ExcessiveEnum {
42-
First, Second, Third, Fourth, Fifth, Sixth, Seventh, Eighth, Ninth, Tenth, Eleventh, Twelfth
45+
First,
46+
Second,
47+
Third,
48+
Fourth,
49+
Fifth,
50+
Sixth,
51+
Seventh,
52+
Eighth,
53+
Ninth,
54+
Tenth,
55+
Eleventh,
56+
Twelfth,
4357
}
4458

4559
fn enum_with_excessive_missing_variants() {
4660
match ExcessiveEnum::First {
47-
//~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
48-
49-
ExcessiveEnum::First => ()
61+
//~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
62+
ExcessiveEnum::First => (),
5063
}
5164
}
5265

5366
fn enum_struct_variant() {
5467
match Color::Red {
55-
//~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
68+
//~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
5669
Color::Red => (),
5770
Color::Green => (),
5871
Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (),
59-
Color::CustomRGBA { a: false, r: _, g: _, b: _ } => ()
72+
Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
6073
}
6174
}
6275

6376
enum Enum {
6477
First,
65-
Second(bool)
78+
Second(bool),
6679
}
6780

6881
fn vectors_with_nested_enums() {
6982
let x: &'static [Enum] = &[Enum::First, Enum::Second(false)];
7083
match *x {
71-
//~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
84+
//~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
7285
[] => (),
7386
[_] => (),
7487
[Enum::First, _] => (),
7588
[Enum::Second(true), Enum::First] => (),
7689
[Enum::Second(true), Enum::Second(true)] => (),
7790
[Enum::Second(false), _] => (),
78-
[_, _, ref tail @ .., _] => ()
91+
[_, _, ref tail @ .., _] => (),
7992
}
8093
}
8194

8295
fn missing_nil() {
8396
match ((), false) {
84-
//~^ ERROR non-exhaustive patterns: `((), false)` not covered
85-
((), true) => ()
97+
//~^ ERROR non-exhaustive patterns: `((), false)` not covered
98+
((), true) => (),
8699
}
87100
}
88101

‎tests/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr

+25-25
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([_, _, _, _]) }` not covered
1+
error[E0004]: non-exhaustive patterns: `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
22
--> $DIR/non-exhaustive-pattern-witness.rs:7:11
33
|
44
LL | match (Foo { first: true, second: None }) {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { first: false, second: Some([_, _, _, _]) }` not covered
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo { first: false, second: Some([0_usize, _, _, _]) }` and `Foo { first: false, second: Some([2_usize.., _, _, _]) }` not covered
66
|
77
note: `Foo` defined here
88
--> $DIR/non-exhaustive-pattern-witness.rs:1:8
99
|
1010
LL | struct Foo {
1111
| ^^^
1212
= note: the matched value is of type `Foo`
13-
= note: `usize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
14-
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
15-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
13+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
1614
|
1715
LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (),
18-
LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!()
16+
LL ~ Foo { first: false, second: Some([0_usize, _, _, _]) } | Foo { first: false, second: Some([2_usize.., _, _, _]) } => todo!(),
1917
|
2018

2119
error[E0004]: non-exhaustive patterns: `Color::Red` not covered
@@ -35,52 +33,54 @@ LL | Red,
3533
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
3634
|
3735
LL ~ Color::Green => (),
38-
LL + Color::Red => todo!()
36+
LL ~ Color::Red => todo!(),
3937
|
4038

4139
error[E0004]: non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered
42-
--> $DIR/non-exhaustive-pattern-witness.rs:35:11
40+
--> $DIR/non-exhaustive-pattern-witness.rs:38:11
4341
|
4442
LL | match Direction::North {
4543
| ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered
4644
|
4745
note: `Direction` defined here
48-
--> $DIR/non-exhaustive-pattern-witness.rs:31:12
46+
--> $DIR/non-exhaustive-pattern-witness.rs:32:5
4947
|
5048
LL | enum Direction {
5149
| ---------
52-
LL | North, East, South, West
53-
| ^^^^ ^^^^^ ^^^^ not covered
54-
| | |
55-
| | not covered
56-
| not covered
50+
LL | North,
51+
LL | East,
52+
| ^^^^ not covered
53+
LL | South,
54+
| ^^^^^ not covered
55+
LL | West,
56+
| ^^^^ not covered
5757
= note: the matched value is of type `Direction`
5858
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
5959
|
6060
LL ~ Direction::North => (),
61-
LL + Direction::East | Direction::South | Direction::West => todo!()
61+
LL ~ Direction::East | Direction::South | Direction::West => todo!(),
6262
|
6363

6464
error[E0004]: non-exhaustive patterns: `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
65-
--> $DIR/non-exhaustive-pattern-witness.rs:46:11
65+
--> $DIR/non-exhaustive-pattern-witness.rs:60:11
6666
|
6767
LL | match ExcessiveEnum::First {
6868
| ^^^^^^^^^^^^^^^^^^^^ patterns `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered
6969
|
7070
note: `ExcessiveEnum` defined here
71-
--> $DIR/non-exhaustive-pattern-witness.rs:41:6
71+
--> $DIR/non-exhaustive-pattern-witness.rs:44:6
7272
|
7373
LL | enum ExcessiveEnum {
7474
| ^^^^^^^^^^^^^
7575
= note: the matched value is of type `ExcessiveEnum`
7676
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
7777
|
7878
LL ~ ExcessiveEnum::First => (),
79-
LL + _ => todo!()
79+
LL ~ _ => todo!(),
8080
|
8181

8282
error[E0004]: non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered
83-
--> $DIR/non-exhaustive-pattern-witness.rs:54:11
83+
--> $DIR/non-exhaustive-pattern-witness.rs:67:11
8484
|
8585
LL | match Color::Red {
8686
| ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered
@@ -91,17 +91,17 @@ note: `Color` defined here
9191
LL | enum Color {
9292
| -----
9393
...
94-
LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 }
94+
LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 },
9595
| ^^^^^^^^^^ not covered
9696
= note: the matched value is of type `Color`
9797
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
9898
|
9999
LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (),
100-
LL + Color::CustomRGBA { a: true, .. } => todo!()
100+
LL ~ Color::CustomRGBA { a: true, .. } => todo!(),
101101
|
102102

103103
error[E0004]: non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered
104-
--> $DIR/non-exhaustive-pattern-witness.rs:70:11
104+
--> $DIR/non-exhaustive-pattern-witness.rs:83:11
105105
|
106106
LL | match *x {
107107
| ^^ pattern `[Enum::Second(true), Enum::Second(false)]` not covered
@@ -110,11 +110,11 @@ LL | match *x {
110110
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
111111
|
112112
LL ~ [_, _, ref tail @ .., _] => (),
113-
LL + [Enum::Second(true), Enum::Second(false)] => todo!()
113+
LL ~ [Enum::Second(true), Enum::Second(false)] => todo!(),
114114
|
115115

116116
error[E0004]: non-exhaustive patterns: `((), false)` not covered
117-
--> $DIR/non-exhaustive-pattern-witness.rs:83:11
117+
--> $DIR/non-exhaustive-pattern-witness.rs:96:11
118118
|
119119
LL | match ((), false) {
120120
| ^^^^^^^^^^^ pattern `((), false)` not covered
@@ -123,7 +123,7 @@ LL | match ((), false) {
123123
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
124124
|
125125
LL ~ ((), true) => (),
126-
LL + ((), false) => todo!()
126+
LL ~ ((), false) => todo!(),
127127
|
128128

129129
error: aborting due to 7 previous errors

‎tests/ui/pattern/usefulness/refutable-pattern-errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
1+
fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) {}
22
//~^ ERROR refutable pattern in function argument
3-
//~| `(_, _)` not covered
3+
//~| `(..=0_isize, _)` and `(2_isize.., _)` not covered
44

55
fn main() {
66
let (1, (Some(1), 2..=3)) = (1, (None, 2));

‎tests/ui/pattern/usefulness/refutable-pattern-errors.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0005]: refutable pattern in function argument
22
--> $DIR/refutable-pattern-errors.rs:1:9
33
|
4-
LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
5-
| ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered
4+
LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) {}
5+
| ^^^^^^^^^^^^^^^^^^^^^ patterns `(..=0_isize, _)` and `(2_isize.., _)` not covered
66
|
77
= note: the matched value is of type `(isize, (Option<isize>, isize))`
88

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fn main() {
22
let f = |3: isize| println!("hello");
33
//~^ ERROR refutable pattern in function argument
4-
//~| `_` not covered
4+
//~| `..=2_isize` and `4_isize..` not covered
55
f(4);
66
}

‎tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0005]: refutable pattern in function argument
22
--> $DIR/refutable-pattern-in-fn-arg.rs:2:14
33
|
44
LL | let f = |3: isize| println!("hello");
5-
| ^ pattern `_` not covered
5+
| ^ patterns `..=2_isize` and `4_isize..` not covered
66
|
77
= note: the matched value is of type `isize`
88
help: alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits

‎tests/ui/pattern/usefulness/tuple-struct-nonexhaustive.stderr

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
1-
error[E0004]: non-exhaustive patterns: `Foo(_, _)` not covered
1+
error[E0004]: non-exhaustive patterns: `Foo(..=0_isize, _)` and `Foo(3_isize.., _)` not covered
22
--> $DIR/tuple-struct-nonexhaustive.rs:5:11
33
|
44
LL | match x {
5-
| ^ pattern `Foo(_, _)` not covered
5+
| ^ patterns `Foo(..=0_isize, _)` and `Foo(3_isize.., _)` not covered
66
|
77
note: `Foo` defined here
88
--> $DIR/tuple-struct-nonexhaustive.rs:1:8
99
|
1010
LL | struct Foo(isize, isize);
1111
| ^^^
1212
= note: the matched value is of type `Foo`
13-
= note: `isize` does not have a fixed maximum value, so a wildcard `_` is necessary to match exhaustively
14-
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
15-
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
13+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
1614
|
1715
LL ~ Foo(2, b) => println!("{}", b),
18-
LL + Foo(_, _) => todo!()
16+
LL + Foo(..=0_isize, _) | Foo(3_isize.., _) => todo!()
1917
|
2018

2119
error: aborting due to previous error

0 commit comments

Comments
 (0)
Please sign in to comment.