Auto merge of #79523 - Nadrieril:fix-usize-ranges, r=varkor
Fix overlap detection of `usize`/`isize` range patterns `usize` and `isize` are a bit of a special case in the match usefulness algorithm, because the range of values they contain depends on the platform. Specifically, we don't want `0..usize::MAX` to count as an exhaustive match (see also [`precise_pointer_size_matching`](https://github.com/rust-lang/rust/issues/56354)). The way this was initially implemented is by treating those ranges like float ranges, i.e. with limited cleverness. This means we didn't catch the following as unreachable: ```rust match 0usize { 0..10 => {}, 10..20 => {}, 5..15 => {}, // oops, should be detected as unreachable _ => {}, } ``` This PRs fixes this oversight. Now the only difference between `usize` and `u64` range patterns is in what ranges count as exhaustive. r? `@varkor` `@rustbot` label +A-exhaustiveness-checking
This commit is contained in:
commit
b776d1c3e3
4 changed files with 74 additions and 95 deletions
|
@ -37,14 +37,12 @@ use std::ops::RangeInclusive;
|
||||||
///
|
///
|
||||||
/// `IntRange` is never used to encode an empty range or a "range" that wraps
|
/// `IntRange` is never used to encode an empty range or a "range" that wraps
|
||||||
/// around the (offset) space: i.e., `range.lo <= range.hi`.
|
/// around the (offset) space: i.e., `range.lo <= range.hi`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(super) struct IntRange<'tcx> {
|
pub(super) struct IntRange {
|
||||||
range: RangeInclusive<u128>,
|
range: RangeInclusive<u128>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
span: Span,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> IntRange<'tcx> {
|
impl IntRange {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_integral(ty: Ty<'_>) -> bool {
|
fn is_integral(ty: Ty<'_>) -> bool {
|
||||||
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
|
matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_) | ty::Bool)
|
||||||
|
@ -58,14 +56,8 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
(*self.range.start(), *self.range.end())
|
(*self.range.start(), *self.range.end())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching` feature
|
|
||||||
/// is enabled.
|
|
||||||
fn treat_exhaustively(&self, tcx: TyCtxt<'tcx>) -> bool {
|
|
||||||
!self.ty.is_ptr_sized_integral() || tcx.features().precise_pointer_size_matching
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> {
|
fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u128)> {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Bool => Some((Size::from_bytes(1), 0)),
|
ty::Bool => Some((Size::from_bytes(1), 0)),
|
||||||
ty::Char => Some((Size::from_bytes(4), 0)),
|
ty::Char => Some((Size::from_bytes(4), 0)),
|
||||||
|
@ -79,12 +71,11 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_const(
|
fn from_const<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
value: &Const<'tcx>,
|
value: &Const<'tcx>,
|
||||||
span: Span,
|
) -> Option<IntRange> {
|
||||||
) -> Option<IntRange<'tcx>> {
|
|
||||||
if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
|
if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
|
||||||
let ty = value.ty;
|
let ty = value.ty;
|
||||||
let val = (|| {
|
let val = (|| {
|
||||||
|
@ -101,21 +92,20 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
value.try_eval_bits(tcx, param_env, ty)
|
value.try_eval_bits(tcx, param_env, ty)
|
||||||
})()?;
|
})()?;
|
||||||
let val = val ^ bias;
|
let val = val ^ bias;
|
||||||
Some(IntRange { range: val..=val, ty, span })
|
Some(IntRange { range: val..=val })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_range(
|
fn from_range<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
lo: u128,
|
lo: u128,
|
||||||
hi: u128,
|
hi: u128,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
end: &RangeEnd,
|
end: &RangeEnd,
|
||||||
span: Span,
|
) -> Option<IntRange> {
|
||||||
) -> Option<IntRange<'tcx>> {
|
|
||||||
if Self::is_integral(ty) {
|
if Self::is_integral(ty) {
|
||||||
// Perform a shift if the underlying types are signed,
|
// Perform a shift if the underlying types are signed,
|
||||||
// which makes the interval arithmetic simpler.
|
// which makes the interval arithmetic simpler.
|
||||||
|
@ -126,14 +116,14 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
// This should have been caught earlier by E0030.
|
// This should have been caught earlier by E0030.
|
||||||
bug!("malformed range pattern: {}..={}", lo, (hi - offset));
|
bug!("malformed range pattern: {}..={}", lo, (hi - offset));
|
||||||
}
|
}
|
||||||
Some(IntRange { range: lo..=(hi - offset), ty, span })
|
Some(IntRange { range: lo..=(hi - offset) })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
|
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
|
||||||
fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 {
|
fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Int(ity) => {
|
ty::Int(ity) => {
|
||||||
let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
|
let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
|
||||||
|
@ -147,20 +137,13 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
|
other.range.start() <= self.range.start() && self.range.end() <= other.range.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersection(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Option<Self> {
|
fn intersection(&self, other: &Self) -> Option<Self> {
|
||||||
let ty = self.ty;
|
|
||||||
let (lo, hi) = self.boundaries();
|
let (lo, hi) = self.boundaries();
|
||||||
let (other_lo, other_hi) = other.boundaries();
|
let (other_lo, other_hi) = other.boundaries();
|
||||||
if self.treat_exhaustively(tcx) {
|
if lo <= other_hi && other_lo <= hi {
|
||||||
if lo <= other_hi && other_lo <= hi {
|
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) })
|
||||||
let span = other.span;
|
|
||||||
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), ty, span })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// If the range should not be treated exhaustively, fallback to checking for inclusion.
|
None
|
||||||
if self.is_subrange(other) { Some(self.clone()) } else { None }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,15 +164,15 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
lo == other_hi || hi == other_lo
|
lo == other_hi || hi == other_lo
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_pat(&self, tcx: TyCtxt<'tcx>) -> Pat<'tcx> {
|
fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
||||||
let (lo, hi) = self.boundaries();
|
let (lo, hi) = self.boundaries();
|
||||||
|
|
||||||
let bias = IntRange::signed_bias(tcx, self.ty);
|
let bias = IntRange::signed_bias(tcx, ty);
|
||||||
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
||||||
|
|
||||||
let ty = ty::ParamEnv::empty().and(self.ty);
|
let env = ty::ParamEnv::empty().and(ty);
|
||||||
let lo_const = ty::Const::from_bits(tcx, lo, ty);
|
let lo_const = ty::Const::from_bits(tcx, lo, env);
|
||||||
let hi_const = ty::Const::from_bits(tcx, hi, ty);
|
let hi_const = ty::Const::from_bits(tcx, hi, env);
|
||||||
|
|
||||||
let kind = if lo == hi {
|
let kind = if lo == hi {
|
||||||
PatKind::Constant { value: lo_const }
|
PatKind::Constant { value: lo_const }
|
||||||
|
@ -197,8 +180,7 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
|
PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is a brand new pattern, so we don't reuse `self.span`.
|
Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
|
||||||
Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(kind) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For exhaustive integer matching, some constructors are grouped within other constructors
|
/// For exhaustive integer matching, some constructors are grouped within other constructors
|
||||||
|
@ -233,13 +215,11 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
/// boundaries for each interval range, sort them, then create constructors for each new interval
|
/// boundaries for each interval range, sort them, then create constructors for each new interval
|
||||||
/// between every pair of boundary points. (This essentially sums up to performing the intuitive
|
/// between every pair of boundary points. (This essentially sums up to performing the intuitive
|
||||||
/// merging operation depicted above.)
|
/// merging operation depicted above.)
|
||||||
fn split<'p>(
|
fn split<'p, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
pcx: PatCtxt<'_, 'p, 'tcx>,
|
pcx: PatCtxt<'_, 'p, 'tcx>,
|
||||||
hir_id: Option<HirId>,
|
hir_id: Option<HirId>,
|
||||||
) -> SmallVec<[Constructor<'tcx>; 1]> {
|
) -> SmallVec<[Constructor<'tcx>; 1]> {
|
||||||
let ty = pcx.ty;
|
|
||||||
|
|
||||||
/// Represents a border between 2 integers. Because the intervals spanning borders
|
/// Represents a border between 2 integers. Because the intervals spanning borders
|
||||||
/// must be able to cover every integer, we need to be able to represent
|
/// must be able to cover every integer, we need to be able to represent
|
||||||
/// 2^128 + 1 such borders.
|
/// 2^128 + 1 such borders.
|
||||||
|
@ -250,7 +230,7 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A function for extracting the borders of an integer interval.
|
// A function for extracting the borders of an integer interval.
|
||||||
fn range_borders(r: IntRange<'_>) -> impl Iterator<Item = Border> {
|
fn range_borders(r: IntRange) -> impl Iterator<Item = Border> {
|
||||||
let (lo, hi) = r.range.into_inner();
|
let (lo, hi) = r.range.into_inner();
|
||||||
let from = Border::JustBefore(lo);
|
let from = Border::JustBefore(lo);
|
||||||
let to = match hi.checked_add(1) {
|
let to = match hi.checked_add(1) {
|
||||||
|
@ -268,21 +248,23 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
// class lies between 2 borders.
|
// class lies between 2 borders.
|
||||||
let row_borders = pcx
|
let row_borders = pcx
|
||||||
.matrix
|
.matrix
|
||||||
.head_ctors(pcx.cx)
|
.head_ctors_and_spans(pcx.cx)
|
||||||
.filter_map(|ctor| ctor.as_int_range())
|
.filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
|
||||||
.filter_map(|range| {
|
.filter_map(|(range, span)| {
|
||||||
let intersection = self.intersection(pcx.cx.tcx, &range);
|
let intersection = self.intersection(&range);
|
||||||
let should_lint = self.suspicious_intersection(&range);
|
let should_lint = self.suspicious_intersection(&range);
|
||||||
if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
|
if let (Some(range), 1, true) = (&intersection, row_len, should_lint) {
|
||||||
// FIXME: for now, only check for overlapping ranges on simple range
|
// FIXME: for now, only check for overlapping ranges on simple range
|
||||||
// patterns. Otherwise with the current logic the following is detected
|
// patterns. Otherwise with the current logic the following is detected
|
||||||
// as overlapping:
|
// as overlapping:
|
||||||
// match (10u8, true) {
|
// ```
|
||||||
// (0 ..= 125, false) => {}
|
// match (0u8, true) {
|
||||||
// (126 ..= 255, false) => {}
|
// (0 ..= 125, false) => {}
|
||||||
// (0 ..= 255, true) => {}
|
// (125 ..= 255, true) => {}
|
||||||
// }
|
// _ => {}
|
||||||
overlaps.push(range.clone());
|
// }
|
||||||
|
// ```
|
||||||
|
overlaps.push((range.clone(), span));
|
||||||
}
|
}
|
||||||
intersection
|
intersection
|
||||||
})
|
})
|
||||||
|
@ -291,7 +273,7 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
|
let mut borders: Vec<_> = row_borders.chain(self_borders).collect();
|
||||||
borders.sort_unstable();
|
borders.sort_unstable();
|
||||||
|
|
||||||
self.lint_overlapping_patterns(pcx.cx.tcx, hir_id, ty, overlaps);
|
self.lint_overlapping_patterns(pcx, hir_id, overlaps);
|
||||||
|
|
||||||
// We're going to iterate through every adjacent pair of borders, making sure that
|
// We're going to iterate through every adjacent pair of borders, making sure that
|
||||||
// each represents an interval of nonnegative length, and convert each such
|
// each represents an interval of nonnegative length, and convert each such
|
||||||
|
@ -309,33 +291,32 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
[Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX),
|
[Border::JustBefore(n), Border::AfterMax] => Some(n..=u128::MAX),
|
||||||
[Border::AfterMax, _] => None,
|
[Border::AfterMax, _] => None,
|
||||||
})
|
})
|
||||||
.map(|range| IntRange { range, ty, span: pcx.span })
|
.map(|range| IntRange { range })
|
||||||
.map(IntRange)
|
.map(IntRange)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_overlapping_patterns(
|
fn lint_overlapping_patterns(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
pcx: PatCtxt<'_, '_, '_>,
|
||||||
hir_id: Option<HirId>,
|
hir_id: Option<HirId>,
|
||||||
ty: Ty<'tcx>,
|
overlaps: Vec<(IntRange, Span)>,
|
||||||
overlaps: Vec<IntRange<'tcx>>,
|
|
||||||
) {
|
) {
|
||||||
if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
|
if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) {
|
||||||
tcx.struct_span_lint_hir(
|
pcx.cx.tcx.struct_span_lint_hir(
|
||||||
lint::builtin::OVERLAPPING_PATTERNS,
|
lint::builtin::OVERLAPPING_PATTERNS,
|
||||||
hir_id,
|
hir_id,
|
||||||
self.span,
|
pcx.span,
|
||||||
|lint| {
|
|lint| {
|
||||||
let mut err = lint.build("multiple patterns covering the same range");
|
let mut err = lint.build("multiple patterns covering the same range");
|
||||||
err.span_label(self.span, "overlapping patterns");
|
err.span_label(pcx.span, "overlapping patterns");
|
||||||
for int_range in overlaps {
|
for (int_range, span) in overlaps {
|
||||||
// Use the real type for user display of the ranges:
|
// Use the real type for user display of the ranges:
|
||||||
err.span_label(
|
err.span_label(
|
||||||
int_range.span,
|
span,
|
||||||
&format!(
|
&format!(
|
||||||
"this range overlaps on `{}`",
|
"this range overlaps on `{}`",
|
||||||
IntRange { range: int_range.range, ty, span: DUMMY_SP }.to_pat(tcx),
|
int_range.to_pat(pcx.cx.tcx, pcx.ty),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -346,8 +327,8 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `Constructor::is_covered_by`
|
/// See `Constructor::is_covered_by`
|
||||||
fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
|
fn is_covered_by(&self, other: &Self) -> bool {
|
||||||
if self.intersection(pcx.cx.tcx, other).is_some() {
|
if self.intersection(other).is_some() {
|
||||||
// Constructor splitting should ensure that all intersections we encounter are actually
|
// Constructor splitting should ensure that all intersections we encounter are actually
|
||||||
// inclusions.
|
// inclusions.
|
||||||
assert!(self.is_subrange(other));
|
assert!(self.is_subrange(other));
|
||||||
|
@ -358,13 +339,6 @@ impl<'tcx> IntRange<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
|
|
||||||
impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.range == other.range && self.ty == other.ty
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
enum SliceKind {
|
enum SliceKind {
|
||||||
/// Patterns of length `n` (`[x, y]`).
|
/// Patterns of length `n` (`[x, y]`).
|
||||||
|
@ -558,7 +532,7 @@ pub(super) enum Constructor<'tcx> {
|
||||||
/// Enum variants.
|
/// Enum variants.
|
||||||
Variant(DefId),
|
Variant(DefId),
|
||||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||||
IntRange(IntRange<'tcx>),
|
IntRange(IntRange),
|
||||||
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
||||||
FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
|
FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
|
||||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||||
|
@ -581,7 +555,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
matches!(self, Wildcard)
|
matches!(self, Wildcard)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_int_range(&self) -> Option<&IntRange<'tcx>> {
|
fn as_int_range(&self) -> Option<&IntRange> {
|
||||||
match self {
|
match self {
|
||||||
IntRange(range) => Some(range),
|
IntRange(range) => Some(range),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -616,8 +590,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
Variant(adt_def.variants[variant_index].def_id)
|
Variant(adt_def.variants[variant_index].def_id)
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => {
|
PatKind::Constant { value } => {
|
||||||
if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value, pat.span)
|
if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) {
|
||||||
{
|
|
||||||
IntRange(int_range)
|
IntRange(int_range)
|
||||||
} else {
|
} else {
|
||||||
match pat.ty.kind() {
|
match pat.ty.kind() {
|
||||||
|
@ -641,7 +614,6 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
|
hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
|
||||||
ty,
|
ty,
|
||||||
&end,
|
&end,
|
||||||
pat.span,
|
|
||||||
) {
|
) {
|
||||||
IntRange(int_range)
|
IntRange(int_range)
|
||||||
} else {
|
} else {
|
||||||
|
@ -694,11 +666,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
Wildcard => Constructor::split_wildcard(pcx),
|
Wildcard => Constructor::split_wildcard(pcx),
|
||||||
// Fast-track if the range is trivial. In particular, we don't do the overlapping
|
// Fast-track if the range is trivial. In particular, we don't do the overlapping
|
||||||
// ranges check.
|
// ranges check.
|
||||||
IntRange(ctor_range)
|
IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx, hir_id),
|
||||||
if ctor_range.treat_exhaustively(pcx.cx.tcx) && !ctor_range.is_singleton() =>
|
|
||||||
{
|
|
||||||
ctor_range.split(pcx, hir_id)
|
|
||||||
}
|
|
||||||
Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
|
Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
|
||||||
// Any other constructor can be used unchanged.
|
// Any other constructor can be used unchanged.
|
||||||
_ => smallvec![self.clone()],
|
_ => smallvec![self.clone()],
|
||||||
|
@ -740,9 +708,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
(Single, Single) => true,
|
(Single, Single) => true,
|
||||||
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
||||||
|
|
||||||
(IntRange(self_range), IntRange(other_range)) => {
|
(IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
|
||||||
self_range.is_covered_by(pcx, other_range)
|
|
||||||
}
|
|
||||||
(
|
(
|
||||||
FloatRange(self_from, self_to, self_end),
|
FloatRange(self_from, self_to, self_end),
|
||||||
FloatRange(other_from, other_to, other_end),
|
FloatRange(other_from, other_to, other_end),
|
||||||
|
@ -803,7 +769,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
IntRange(range) => used_ctors
|
IntRange(range) => used_ctors
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|c| c.as_int_range())
|
.filter_map(|c| c.as_int_range())
|
||||||
.any(|other| range.is_covered_by(pcx, other)),
|
.any(|other| range.is_covered_by(other)),
|
||||||
Slice(slice) => used_ctors
|
Slice(slice) => used_ctors
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|c| c.as_slice())
|
.filter_map(|c| c.as_slice())
|
||||||
|
@ -811,7 +777,7 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
// This constructor is never covered by anything else
|
// This constructor is never covered by anything else
|
||||||
NonExhaustive => false,
|
NonExhaustive => false,
|
||||||
Str(..) | FloatRange(..) | Opaque | Wildcard => {
|
Str(..) | FloatRange(..) | Opaque | Wildcard => {
|
||||||
bug!("found unexpected ctor in all_ctors: {:?}", self)
|
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -832,8 +798,7 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
|
||||||
let make_range = |start, end| {
|
let make_range = |start, end| {
|
||||||
IntRange(
|
IntRange(
|
||||||
// `unwrap()` is ok because we know the type is an integer.
|
// `unwrap()` is ok because we know the type is an integer.
|
||||||
IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included, pcx.span)
|
IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
match pcx.ty.kind() {
|
match pcx.ty.kind() {
|
||||||
|
@ -1238,7 +1203,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
|
||||||
},
|
},
|
||||||
&Str(value) => PatKind::Constant { value },
|
&Str(value) => PatKind::Constant { value },
|
||||||
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
|
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
|
||||||
IntRange(range) => return range.to_pat(pcx.cx.tcx),
|
IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
|
||||||
NonExhaustive => PatKind::Wild,
|
NonExhaustive => PatKind::Wild,
|
||||||
Opaque => bug!("we should not try to apply an opaque constructor"),
|
Opaque => bug!("we should not try to apply an opaque constructor"),
|
||||||
Wildcard => bug!(
|
Wildcard => bug!(
|
||||||
|
|
|
@ -535,14 +535,22 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
self.patterns.iter().map(|r| r.head())
|
self.patterns.iter().map(|r| r.head())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over the first constructor of each row
|
/// Iterate over the first constructor of each row.
|
||||||
pub(super) fn head_ctors<'a>(
|
pub(super) fn head_ctors<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
cx: &'a MatchCheckCtxt<'p, 'tcx>,
|
cx: &'a MatchCheckCtxt<'p, 'tcx>,
|
||||||
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'a> + Captures<'p> {
|
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
|
||||||
self.patterns.iter().map(move |r| r.head_ctor(cx))
|
self.patterns.iter().map(move |r| r.head_ctor(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterate over the first constructor and the corresponding span of each row.
|
||||||
|
pub(super) fn head_ctors_and_spans<'a>(
|
||||||
|
&'a self,
|
||||||
|
cx: &'a MatchCheckCtxt<'p, 'tcx>,
|
||||||
|
) -> impl Iterator<Item = (&'a Constructor<'tcx>, Span)> + Captures<'p> {
|
||||||
|
self.patterns.iter().map(move |r| (r.head_ctor(cx), r.head().span))
|
||||||
|
}
|
||||||
|
|
||||||
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
/// This computes `S(constructor, self)`. See top of the file for explanations.
|
||||||
fn specialize_constructor(
|
fn specialize_constructor(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -72,7 +72,7 @@ fn main() {
|
||||||
match 0usize {
|
match 0usize {
|
||||||
0..10 => {},
|
0..10 => {},
|
||||||
10..20 => {},
|
10..20 => {},
|
||||||
5..15 => {}, // FIXME: should be unreachable
|
5..15 => {}, //~ ERROR unreachable pattern
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
// Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are
|
// Chars between '\u{D7FF}' and '\u{E000}' are invalid even though ranges that contain them are
|
||||||
|
|
|
@ -124,6 +124,12 @@ error: unreachable pattern
|
||||||
LL | 5..25 => {},
|
LL | 5..25 => {},
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/reachability.rs:75:9
|
||||||
|
|
|
||||||
|
LL | 5..15 => {},
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
error: unreachable pattern
|
error: unreachable pattern
|
||||||
--> $DIR/reachability.rs:82:9
|
--> $DIR/reachability.rs:82:9
|
||||||
|
|
|
|
||||||
|
@ -142,5 +148,5 @@ error: unreachable pattern
|
||||||
LL | BAR => {}
|
LL | BAR => {}
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to 23 previous errors
|
error: aborting due to 24 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue