mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-10 19:16:51 +00:00
Auto merge of #66129 - Nadrieril:refactor-slice-pat-usefulness, r=varkor
Refactor slice pattern usefulness checking
As a follow up to https://github.com/rust-lang/rust/pull/65874, this PR changes how variable-length slice patterns are handled in usefulness checking. The objectives are: cleaning up that code to make it easier to understand, and paving the way to handling fixed-length slices more cleverly too, for https://github.com/rust-lang/rust/issues/53820.
Before this, variable-length slice patterns were eagerly expanded into a union of fixed-length slices. Now they have their own special constructor, which allows expanding them a bit more lazily.
As a nice side-effect, this improves diagnostics.
This PR shows a slight performance improvement, mostly due to 149792b608
. This will probably have to be reverted in some way when we implement or-patterns.
This commit is contained in:
commit
e3d998492a
@ -586,8 +586,10 @@ enum Constructor<'tcx> {
|
|||||||
ConstantValue(&'tcx ty::Const<'tcx>, Span),
|
ConstantValue(&'tcx ty::Const<'tcx>, Span),
|
||||||
/// Ranges of literal values (`2..=5` and `2..5`).
|
/// Ranges of literal values (`2..=5` and `2..5`).
|
||||||
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
|
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
|
||||||
/// Array patterns of length n.
|
/// Array patterns of length `n`.
|
||||||
Slice(u64),
|
FixedLenSlice(u64),
|
||||||
|
/// Slice patterns. Captures any array constructor of `length >= i + j`.
|
||||||
|
VarLenSlice(u64, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
|
// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
|
||||||
@ -601,7 +603,11 @@ impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> {
|
|||||||
Constructor::ConstantRange(a_start, a_end, a_ty, a_range_end, _),
|
Constructor::ConstantRange(a_start, a_end, a_ty, a_range_end, _),
|
||||||
Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _),
|
Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _),
|
||||||
) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
|
) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
|
||||||
(Constructor::Slice(a), Constructor::Slice(b)) => a == b,
|
(Constructor::FixedLenSlice(a), Constructor::FixedLenSlice(b)) => a == b,
|
||||||
|
(
|
||||||
|
Constructor::VarLenSlice(a_prefix, a_suffix),
|
||||||
|
Constructor::VarLenSlice(b_prefix, b_suffix),
|
||||||
|
) => a_prefix == b_prefix && a_suffix == b_suffix,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -610,7 +616,7 @@ impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> {
|
|||||||
impl<'tcx> Constructor<'tcx> {
|
impl<'tcx> Constructor<'tcx> {
|
||||||
fn is_slice(&self) -> bool {
|
fn is_slice(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Slice { .. } => true,
|
FixedLenSlice { .. } | VarLenSlice { .. } => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -644,7 +650,8 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
ty::Const::from_bits(tcx, *hi, ty),
|
ty::Const::from_bits(tcx, *hi, ty),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Constructor::Slice(val) => format!("[{}]", val),
|
Constructor::FixedLenSlice(val) => format!("[{}]", val),
|
||||||
|
Constructor::VarLenSlice(prefix, suffix) => format!("[{}, .., {}]", prefix, suffix),
|
||||||
_ => bug!("bad constructor being displayed: `{:?}", self),
|
_ => bug!("bad constructor being displayed: `{:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -657,31 +664,114 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
other_ctors: &Vec<Constructor<'tcx>>,
|
other_ctors: &Vec<Constructor<'tcx>>,
|
||||||
) -> Vec<Constructor<'tcx>> {
|
) -> Vec<Constructor<'tcx>> {
|
||||||
let mut refined_ctors = vec![self.clone()];
|
match *self {
|
||||||
for other_ctor in other_ctors {
|
// Those constructors can only match themselves.
|
||||||
if other_ctor == self {
|
Single | Variant(_) => {
|
||||||
// If a constructor appears in a `match` arm, we can
|
if other_ctors.iter().any(|c| c == self) {
|
||||||
// eliminate it straight away.
|
vec![]
|
||||||
refined_ctors = vec![]
|
} else {
|
||||||
} else if let Some(interval) = IntRange::from_ctor(tcx, param_env, other_ctor) {
|
vec![self.clone()]
|
||||||
// Refine the required constructors for the type by subtracting
|
}
|
||||||
// the range defined by the current constructor pattern.
|
|
||||||
refined_ctors = interval.subtract_from(tcx, param_env, refined_ctors);
|
|
||||||
}
|
}
|
||||||
|
FixedLenSlice(self_len) => {
|
||||||
|
let overlaps = |c: &Constructor<'_>| match *c {
|
||||||
|
FixedLenSlice(other_len) => other_len == self_len,
|
||||||
|
VarLenSlice(prefix, suffix) => prefix + suffix <= self_len,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if other_ctors.iter().any(overlaps) { vec![] } else { vec![self.clone()] }
|
||||||
|
}
|
||||||
|
VarLenSlice(..) => {
|
||||||
|
let mut remaining_ctors = vec![self.clone()];
|
||||||
|
|
||||||
// If the constructor patterns that have been considered so far
|
// For each used ctor, subtract from the current set of constructors.
|
||||||
// already cover the entire range of values, then we know the
|
// Naming: we remove the "neg" constructors from the "pos" ones.
|
||||||
// constructor is not missing, and we can move on to the next one.
|
// Remember, `VarLenSlice(i, j)` covers the union of `FixedLenSlice` from
|
||||||
if refined_ctors.is_empty() {
|
// `i + j` to infinity.
|
||||||
break;
|
for neg_ctor in other_ctors {
|
||||||
|
remaining_ctors = remaining_ctors
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|pos_ctor| -> SmallVec<[Constructor<'tcx>; 1]> {
|
||||||
|
// Compute `pos_ctor \ neg_ctor`.
|
||||||
|
match (&pos_ctor, neg_ctor) {
|
||||||
|
(&FixedLenSlice(pos_len), &VarLenSlice(neg_prefix, neg_suffix)) => {
|
||||||
|
let neg_len = neg_prefix + neg_suffix;
|
||||||
|
if neg_len <= pos_len {
|
||||||
|
smallvec![]
|
||||||
|
} else {
|
||||||
|
smallvec![pos_ctor]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
&VarLenSlice(pos_prefix, pos_suffix),
|
||||||
|
&VarLenSlice(neg_prefix, neg_suffix),
|
||||||
|
) => {
|
||||||
|
let neg_len = neg_prefix + neg_suffix;
|
||||||
|
let pos_len = pos_prefix + pos_suffix;
|
||||||
|
if neg_len <= pos_len {
|
||||||
|
smallvec![]
|
||||||
|
} else {
|
||||||
|
(pos_len..neg_len).map(FixedLenSlice).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(&VarLenSlice(pos_prefix, pos_suffix), &FixedLenSlice(neg_len)) => {
|
||||||
|
let pos_len = pos_prefix + pos_suffix;
|
||||||
|
if neg_len < pos_len {
|
||||||
|
smallvec![pos_ctor]
|
||||||
|
} else {
|
||||||
|
(pos_len..neg_len)
|
||||||
|
.map(FixedLenSlice)
|
||||||
|
// We know that `neg_len + 1 >= pos_len >= pos_suffix`.
|
||||||
|
.chain(Some(VarLenSlice(
|
||||||
|
neg_len + 1 - pos_suffix,
|
||||||
|
pos_suffix,
|
||||||
|
)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ if pos_ctor == *neg_ctor => smallvec![],
|
||||||
|
_ => smallvec![pos_ctor],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// If the constructors that have been considered so far already cover
|
||||||
|
// the entire range of `self`, no need to look at more constructors.
|
||||||
|
if remaining_ctors.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining_ctors
|
||||||
|
}
|
||||||
|
ConstantRange(..) | ConstantValue(..) => {
|
||||||
|
let mut remaining_ctors = vec![self.clone()];
|
||||||
|
for other_ctor in other_ctors {
|
||||||
|
if other_ctor == self {
|
||||||
|
// If a constructor appears in a `match` arm, we can
|
||||||
|
// eliminate it straight away.
|
||||||
|
remaining_ctors = vec![]
|
||||||
|
} else if let Some(interval) = IntRange::from_ctor(tcx, param_env, other_ctor) {
|
||||||
|
// Refine the required constructors for the type by subtracting
|
||||||
|
// the range defined by the current constructor pattern.
|
||||||
|
remaining_ctors = interval.subtract_from(tcx, param_env, remaining_ctors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the constructor patterns that have been considered so far
|
||||||
|
// already cover the entire range of values, then we know the
|
||||||
|
// constructor is not missing, and we can move on to the next one.
|
||||||
|
if remaining_ctors.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a constructor has not been matched, then it is missing.
|
||||||
|
// We add `remaining_ctors` instead of `self`, because then we can
|
||||||
|
// provide more detailed error information about precisely which
|
||||||
|
// ranges have been omitted.
|
||||||
|
remaining_ctors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a constructor has not been matched, then it is missing.
|
|
||||||
// We add `refined_ctors` instead of `self`, because then we can
|
|
||||||
// provide more detailed error information about precisely which
|
|
||||||
// ranges have been omitted.
|
|
||||||
refined_ctors
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This returns one wildcard pattern for each argument to this constructor.
|
/// This returns one wildcard pattern for each argument to this constructor.
|
||||||
@ -689,12 +779,68 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> impl Iterator<Item = Pat<'tcx>> + DoubleEndedIterator {
|
) -> Vec<Pat<'tcx>> {
|
||||||
constructor_sub_pattern_tys(cx, self, ty).into_iter().map(|ty| Pat {
|
debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
|
||||||
ty,
|
match ty.kind {
|
||||||
span: DUMMY_SP,
|
ty::Tuple(ref fs) => {
|
||||||
kind: box PatKind::Wild,
|
fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
|
||||||
})
|
}
|
||||||
|
ty::Slice(ty) | ty::Array(ty, _) => match *self {
|
||||||
|
FixedLenSlice(length) => (0..length).map(|_| Pat::wildcard_from_ty(ty)).collect(),
|
||||||
|
VarLenSlice(prefix, suffix) => {
|
||||||
|
(0..prefix + suffix).map(|_| Pat::wildcard_from_ty(ty)).collect()
|
||||||
|
}
|
||||||
|
ConstantValue(..) => vec![],
|
||||||
|
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
|
||||||
|
},
|
||||||
|
ty::Ref(_, rty, _) => vec![Pat::wildcard_from_ty(rty)],
|
||||||
|
ty::Adt(adt, substs) => {
|
||||||
|
if adt.is_box() {
|
||||||
|
// Use T as the sub pattern type of Box<T>.
|
||||||
|
vec![Pat::wildcard_from_ty(substs.type_at(0))]
|
||||||
|
} else {
|
||||||
|
let variant = &adt.variants[self.variant_index_for_adt(cx, adt)];
|
||||||
|
let is_non_exhaustive =
|
||||||
|
variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
|
||||||
|
variant
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let is_visible =
|
||||||
|
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
||||||
|
let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
|
||||||
|
match (is_visible, is_non_exhaustive, is_uninhabited) {
|
||||||
|
// Treat all uninhabited types in non-exhaustive variants as
|
||||||
|
// `TyErr`.
|
||||||
|
(_, true, true) => cx.tcx.types.err,
|
||||||
|
// Treat all non-visible fields as `TyErr`. They can't appear in
|
||||||
|
// any other pattern from this match (because they are private), so
|
||||||
|
// their type does not matter - but we don't want to know they are
|
||||||
|
// uninhabited.
|
||||||
|
(false, ..) => cx.tcx.types.err,
|
||||||
|
(true, ..) => {
|
||||||
|
let ty = field.ty(cx.tcx, substs);
|
||||||
|
match ty.kind {
|
||||||
|
// If the field type returned is an array of an unknown
|
||||||
|
// size return an TyErr.
|
||||||
|
ty::Array(_, len)
|
||||||
|
if len
|
||||||
|
.try_eval_usize(cx.tcx, cx.param_env)
|
||||||
|
.is_none() =>
|
||||||
|
{
|
||||||
|
cx.tcx.types.err
|
||||||
|
}
|
||||||
|
_ => ty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(Pat::wildcard_from_ty)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This computes the arity of a constructor. The arity of a constructor
|
/// This computes the arity of a constructor. The arity of a constructor
|
||||||
@ -707,7 +853,8 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
match ty.kind {
|
match ty.kind {
|
||||||
ty::Tuple(ref fs) => fs.len() as u64,
|
ty::Tuple(ref fs) => fs.len() as u64,
|
||||||
ty::Slice(..) | ty::Array(..) => match *self {
|
ty::Slice(..) | ty::Array(..) => match *self {
|
||||||
Slice(length) => length,
|
FixedLenSlice(length) => length,
|
||||||
|
VarLenSlice(prefix, suffix) => prefix + suffix,
|
||||||
ConstantValue(..) => 0,
|
ConstantValue(..) => 0,
|
||||||
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
|
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
|
||||||
},
|
},
|
||||||
@ -764,9 +911,18 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
|
|
||||||
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
|
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
|
||||||
|
|
||||||
ty::Slice(_) | ty::Array(..) => {
|
ty::Slice(_) | ty::Array(..) => match self {
|
||||||
PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
|
FixedLenSlice(_) => {
|
||||||
}
|
PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
|
||||||
|
}
|
||||||
|
VarLenSlice(prefix_len, _suffix_len) => {
|
||||||
|
let prefix = subpatterns.by_ref().take(*prefix_len as usize).collect();
|
||||||
|
let suffix = subpatterns.collect();
|
||||||
|
let wild = Pat::wildcard_from_ty(ty);
|
||||||
|
PatKind::Slice { prefix, slice: Some(wild), suffix }
|
||||||
|
}
|
||||||
|
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
|
||||||
|
},
|
||||||
|
|
||||||
_ => match *self {
|
_ => match *self {
|
||||||
ConstantValue(value, _) => PatKind::Constant { value },
|
ConstantValue(value, _) => PatKind::Constant { value },
|
||||||
@ -784,7 +940,7 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
|
|
||||||
/// Like `apply`, but where all the subpatterns are wildcards `_`.
|
/// Like `apply`, but where all the subpatterns are wildcards `_`.
|
||||||
fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
|
||||||
let subpatterns = self.wildcard_subpatterns(cx, ty).rev();
|
let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
|
||||||
self.apply(cx, ty, subpatterns)
|
self.apply(cx, ty, subpatterns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -831,7 +987,7 @@ impl<'tcx> Usefulness<'tcx> {
|
|||||||
fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
|
fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
|
||||||
match self {
|
match self {
|
||||||
UsefulWithWitness(witnesses) => {
|
UsefulWithWitness(witnesses) => {
|
||||||
let wild = Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
|
let wild = Pat::wildcard_from_ty(ty);
|
||||||
UsefulWithWitness(
|
UsefulWithWitness(
|
||||||
witnesses
|
witnesses
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -884,7 +1040,6 @@ pub enum WitnessPreference {
|
|||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct PatCtxt<'tcx> {
|
struct PatCtxt<'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
max_slice_length: u64,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -980,14 +1135,14 @@ fn all_constructors<'a, 'tcx>(
|
|||||||
.collect(),
|
.collect(),
|
||||||
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
|
ty::Array(ref sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
|
||||||
let len = len.eval_usize(cx.tcx, cx.param_env);
|
let len = len.eval_usize(cx.tcx, cx.param_env);
|
||||||
if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![Slice(len)] }
|
if len != 0 && cx.is_uninhabited(sub_ty) { vec![] } else { vec![FixedLenSlice(len)] }
|
||||||
}
|
}
|
||||||
// Treat arrays of a constant but unknown length like slices.
|
// Treat arrays of a constant but unknown length like slices.
|
||||||
ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
|
ty::Array(ref sub_ty, _) | ty::Slice(ref sub_ty) => {
|
||||||
if cx.is_uninhabited(sub_ty) {
|
if cx.is_uninhabited(sub_ty) {
|
||||||
vec![Slice(0)]
|
vec![FixedLenSlice(0)]
|
||||||
} else {
|
} else {
|
||||||
(0..pcx.max_slice_length + 1).map(|length| Slice(length)).collect()
|
vec![VarLenSlice(0, 0)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Adt(def, substs) if def.is_enum() => def
|
ty::Adt(def, substs) if def.is_enum() => def
|
||||||
@ -1042,108 +1197,6 @@ fn all_constructors<'a, 'tcx>(
|
|||||||
ctors
|
ctors
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_slice_length<'p, 'a, 'tcx, I>(cx: &mut MatchCheckCtxt<'a, 'tcx>, patterns: I) -> u64
|
|
||||||
where
|
|
||||||
I: Iterator<Item = &'p Pat<'tcx>>,
|
|
||||||
'tcx: 'p,
|
|
||||||
{
|
|
||||||
// The exhaustiveness-checking paper does not include any details on
|
|
||||||
// checking variable-length slice patterns. However, they are matched
|
|
||||||
// by an infinite collection of fixed-length array patterns.
|
|
||||||
//
|
|
||||||
// Checking the infinite set directly would take an infinite amount
|
|
||||||
// of time. However, it turns out that for each finite set of
|
|
||||||
// patterns `P`, all sufficiently large array lengths are equivalent:
|
|
||||||
//
|
|
||||||
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
|
|
||||||
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
|
|
||||||
// `sₘ` for each sufficiently-large length `m` that applies to exactly
|
|
||||||
// the same subset of `P`.
|
|
||||||
//
|
|
||||||
// Because of that, each witness for reachability-checking from one
|
|
||||||
// of the sufficiently-large lengths can be transformed to an
|
|
||||||
// equally-valid witness from any other length, so we only have
|
|
||||||
// to check slice lengths from the "minimal sufficiently-large length"
|
|
||||||
// and below.
|
|
||||||
//
|
|
||||||
// Note that the fact that there is a *single* `sₘ` for each `m`
|
|
||||||
// not depending on the specific pattern in `P` is important: if
|
|
||||||
// you look at the pair of patterns
|
|
||||||
// `[true, ..]`
|
|
||||||
// `[.., false]`
|
|
||||||
// Then any slice of length ≥1 that matches one of these two
|
|
||||||
// patterns can be trivially turned to a slice of any
|
|
||||||
// other length ≥1 that matches them and vice-versa - for
|
|
||||||
// but the slice from length 2 `[false, true]` that matches neither
|
|
||||||
// of these patterns can't be turned to a slice from length 1 that
|
|
||||||
// matches neither of these patterns, so we have to consider
|
|
||||||
// slices from length 2 there.
|
|
||||||
//
|
|
||||||
// Now, to see that that length exists and find it, observe that slice
|
|
||||||
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
|
|
||||||
// "variable-length" patterns (`[_, .., _]`).
|
|
||||||
//
|
|
||||||
// For fixed-length patterns, all slices with lengths *longer* than
|
|
||||||
// the pattern's length have the same outcome (of not matching), so
|
|
||||||
// as long as `L` is greater than the pattern's length we can pick
|
|
||||||
// any `sₘ` from that length and get the same result.
|
|
||||||
//
|
|
||||||
// For variable-length patterns, the situation is more complicated,
|
|
||||||
// because as seen above the precise value of `sₘ` matters.
|
|
||||||
//
|
|
||||||
// However, for each variable-length pattern `p` with a prefix of length
|
|
||||||
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
|
|
||||||
// `slₚ` elements are examined.
|
|
||||||
//
|
|
||||||
// Therefore, as long as `L` is positive (to avoid concerns about empty
|
|
||||||
// types), all elements after the maximum prefix length and before
|
|
||||||
// the maximum suffix length are not examined by any variable-length
|
|
||||||
// pattern, and therefore can be added/removed without affecting
|
|
||||||
// them - creating equivalent patterns from any sufficiently-large
|
|
||||||
// length.
|
|
||||||
//
|
|
||||||
// Of course, if fixed-length patterns exist, we must be sure
|
|
||||||
// that our length is large enough to miss them all, so
|
|
||||||
// we can pick `L = max(FIXED_LEN+1 ∪ {max(PREFIX_LEN) + max(SUFFIX_LEN)})`
|
|
||||||
//
|
|
||||||
// for example, with the above pair of patterns, all elements
|
|
||||||
// but the first and last can be added/removed, so any
|
|
||||||
// witness of length ≥2 (say, `[false, false, true]`) can be
|
|
||||||
// turned to a witness from any other length ≥2.
|
|
||||||
|
|
||||||
let mut max_prefix_len = 0;
|
|
||||||
let mut max_suffix_len = 0;
|
|
||||||
let mut max_fixed_len = 0;
|
|
||||||
|
|
||||||
for row in patterns {
|
|
||||||
match *row.kind {
|
|
||||||
PatKind::Constant { value } => {
|
|
||||||
// extract the length of an array/slice from a constant
|
|
||||||
match (value.val, &value.ty.kind) {
|
|
||||||
(_, ty::Array(_, n)) => {
|
|
||||||
max_fixed_len = cmp::max(max_fixed_len, n.eval_usize(cx.tcx, cx.param_env))
|
|
||||||
}
|
|
||||||
(ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
|
|
||||||
max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PatKind::Slice { ref prefix, slice: None, ref suffix } => {
|
|
||||||
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
|
|
||||||
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
|
|
||||||
}
|
|
||||||
PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
|
|
||||||
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
|
|
||||||
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmp::max(max_fixed_len + 1, max_prefix_len + max_suffix_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An inclusive interval, used for precise integer exhaustiveness checking.
|
/// An inclusive interval, used for precise integer exhaustiveness checking.
|
||||||
/// `IntRange`s always store a contiguous range. This means that values are
|
/// `IntRange`s always store a contiguous range. This means that values are
|
||||||
/// encoded such that `0` encodes the minimum value for the integer,
|
/// encoded such that `0` encodes the minimum value for the integer,
|
||||||
@ -1508,20 +1561,19 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
|||||||
// introducing uninhabited patterns for inaccessible fields. We
|
// introducing uninhabited patterns for inaccessible fields. We
|
||||||
// need to figure out how to model that.
|
// need to figure out how to model that.
|
||||||
ty,
|
ty,
|
||||||
max_slice_length: max_slice_length(cx, matrix.heads().chain(Some(v.head()))),
|
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
|
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
|
||||||
|
|
||||||
if let Some(constructors) = pat_constructors(cx, v.head(), pcx) {
|
if let Some(constructor) = pat_constructor(cx, v.head(), pcx) {
|
||||||
debug!("is_useful - expanding constructors: {:#?}", constructors);
|
debug!("is_useful - expanding constructor: {:#?}", constructor);
|
||||||
split_grouped_constructors(
|
split_grouped_constructors(
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
cx.param_env,
|
cx.param_env,
|
||||||
constructors,
|
pcx,
|
||||||
|
vec![constructor],
|
||||||
matrix,
|
matrix,
|
||||||
pcx.ty,
|
|
||||||
pcx.span,
|
pcx.span,
|
||||||
Some(hir_id),
|
Some(hir_id),
|
||||||
)
|
)
|
||||||
@ -1533,7 +1585,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
|||||||
debug!("is_useful - expanding wildcard");
|
debug!("is_useful - expanding wildcard");
|
||||||
|
|
||||||
let used_ctors: Vec<Constructor<'_>> =
|
let used_ctors: Vec<Constructor<'_>> =
|
||||||
matrix.heads().flat_map(|p| pat_constructors(cx, p, pcx).unwrap_or(vec![])).collect();
|
matrix.heads().filter_map(|p| pat_constructor(cx, p, pcx)).collect();
|
||||||
debug!("used_ctors = {:#?}", used_ctors);
|
debug!("used_ctors = {:#?}", used_ctors);
|
||||||
// `all_ctors` are all the constructors for the given type, which
|
// `all_ctors` are all the constructors for the given type, which
|
||||||
// should all be represented (or caught with the wild pattern `_`).
|
// should all be represented (or caught with the wild pattern `_`).
|
||||||
@ -1583,19 +1635,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
|
|||||||
|
|
||||||
if missing_ctors.is_empty() && !is_non_exhaustive {
|
if missing_ctors.is_empty() && !is_non_exhaustive {
|
||||||
let (all_ctors, _) = missing_ctors.into_inner();
|
let (all_ctors, _) = missing_ctors.into_inner();
|
||||||
split_grouped_constructors(
|
split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
|
||||||
cx.tcx,
|
.into_iter()
|
||||||
cx.param_env,
|
.map(|c| {
|
||||||
all_ctors,
|
is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
|
||||||
matrix,
|
})
|
||||||
pcx.ty,
|
.find(|result| result.is_useful())
|
||||||
DUMMY_SP,
|
.unwrap_or(NotUseful)
|
||||||
None,
|
|
||||||
)
|
|
||||||
.into_iter()
|
|
||||||
.map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
|
|
||||||
.find(|result| result.is_useful())
|
|
||||||
.unwrap_or(NotUseful)
|
|
||||||
} else {
|
} else {
|
||||||
let matrix = matrix.specialize_wildcard();
|
let matrix = matrix.specialize_wildcard();
|
||||||
let v = v.to_tail();
|
let v = v.to_tail();
|
||||||
@ -1673,7 +1719,7 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
|
|||||||
) -> Usefulness<'tcx> {
|
) -> Usefulness<'tcx> {
|
||||||
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
|
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
|
||||||
|
|
||||||
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty).collect();
|
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty);
|
||||||
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
|
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
|
||||||
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
|
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
|
||||||
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
|
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
|
||||||
@ -1682,44 +1728,39 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
|
|||||||
.unwrap_or(NotUseful)
|
.unwrap_or(NotUseful)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the constructors that the given pattern can be specialized to.
|
/// Determines the constructor that the given pattern can be specialized to.
|
||||||
///
|
|
||||||
/// In most cases, there's only one constructor that a specific pattern
|
|
||||||
/// represents, such as a specific enum variant or a specific literal value.
|
|
||||||
/// Slice patterns, however, can match slices of different lengths. For instance,
|
|
||||||
/// `[a, b, tail @ ..]` can match a slice of length 2, 3, 4 and so on.
|
|
||||||
///
|
|
||||||
/// Returns `None` in case of a catch-all, which can't be specialized.
|
/// Returns `None` in case of a catch-all, which can't be specialized.
|
||||||
fn pat_constructors<'tcx>(
|
fn pat_constructor<'tcx>(
|
||||||
cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
cx: &mut MatchCheckCtxt<'_, 'tcx>,
|
||||||
pat: &Pat<'tcx>,
|
pat: &Pat<'tcx>,
|
||||||
pcx: PatCtxt<'tcx>,
|
pcx: PatCtxt<'tcx>,
|
||||||
) -> Option<Vec<Constructor<'tcx>>> {
|
) -> Option<Constructor<'tcx>> {
|
||||||
match *pat.kind {
|
match *pat.kind {
|
||||||
PatKind::AscribeUserType { ref subpattern, .. } => pat_constructors(cx, subpattern, pcx),
|
PatKind::AscribeUserType { ref subpattern, .. } => pat_constructor(cx, subpattern, pcx),
|
||||||
PatKind::Binding { .. } | PatKind::Wild => None,
|
PatKind::Binding { .. } | PatKind::Wild => None,
|
||||||
PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(vec![Single]),
|
PatKind::Leaf { .. } | PatKind::Deref { .. } => Some(Single),
|
||||||
PatKind::Variant { adt_def, variant_index, .. } => {
|
PatKind::Variant { adt_def, variant_index, .. } => {
|
||||||
Some(vec![Variant(adt_def.variants[variant_index].def_id)])
|
Some(Variant(adt_def.variants[variant_index].def_id))
|
||||||
}
|
}
|
||||||
PatKind::Constant { value } => Some(vec![ConstantValue(value, pat.span)]),
|
PatKind::Constant { value } => Some(ConstantValue(value, pat.span)),
|
||||||
PatKind::Range(PatRange { lo, hi, end }) => Some(vec![ConstantRange(
|
PatKind::Range(PatRange { lo, hi, end }) => Some(ConstantRange(
|
||||||
lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
|
lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
|
||||||
hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
|
hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
|
||||||
lo.ty,
|
lo.ty,
|
||||||
end,
|
end,
|
||||||
pat.span,
|
pat.span,
|
||||||
)]),
|
)),
|
||||||
PatKind::Array { .. } => match pcx.ty.kind {
|
PatKind::Array { .. } => match pcx.ty.kind {
|
||||||
ty::Array(_, length) => Some(vec![Slice(length.eval_usize(cx.tcx, cx.param_env))]),
|
ty::Array(_, length) => Some(FixedLenSlice(length.eval_usize(cx.tcx, cx.param_env))),
|
||||||
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty),
|
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty),
|
||||||
},
|
},
|
||||||
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||||
let pat_len = prefix.len() as u64 + suffix.len() as u64;
|
let prefix = prefix.len() as u64;
|
||||||
|
let suffix = suffix.len() as u64;
|
||||||
if slice.is_some() {
|
if slice.is_some() {
|
||||||
Some((pat_len..pcx.max_slice_length + 1).map(Slice).collect())
|
Some(VarLenSlice(prefix, suffix))
|
||||||
} else {
|
} else {
|
||||||
Some(vec![Slice(pat_len)])
|
Some(FixedLenSlice(prefix + suffix))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PatKind::Or { .. } => {
|
PatKind::Or { .. } => {
|
||||||
@ -1728,68 +1769,6 @@ fn pat_constructors<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This computes the types of the sub patterns that a constructor should be
|
|
||||||
/// expanded to.
|
|
||||||
///
|
|
||||||
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
|
|
||||||
fn constructor_sub_pattern_tys<'a, 'tcx>(
|
|
||||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
|
||||||
ctor: &Constructor<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> Vec<Ty<'tcx>> {
|
|
||||||
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
|
|
||||||
match ty.kind {
|
|
||||||
ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(),
|
|
||||||
ty::Slice(ty) | ty::Array(ty, _) => match *ctor {
|
|
||||||
Slice(length) => (0..length).map(|_| ty).collect(),
|
|
||||||
ConstantValue(..) => vec![],
|
|
||||||
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
|
|
||||||
},
|
|
||||||
ty::Ref(_, rty, _) => vec![rty],
|
|
||||||
ty::Adt(adt, substs) => {
|
|
||||||
if adt.is_box() {
|
|
||||||
// Use T as the sub pattern type of Box<T>.
|
|
||||||
vec![substs.type_at(0)]
|
|
||||||
} else {
|
|
||||||
let variant = &adt.variants[ctor.variant_index_for_adt(cx, adt)];
|
|
||||||
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(ty);
|
|
||||||
variant
|
|
||||||
.fields
|
|
||||||
.iter()
|
|
||||||
.map(|field| {
|
|
||||||
let is_visible =
|
|
||||||
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
|
|
||||||
let is_uninhabited = cx.is_uninhabited(field.ty(cx.tcx, substs));
|
|
||||||
match (is_visible, is_non_exhaustive, is_uninhabited) {
|
|
||||||
// Treat all uninhabited types in non-exhaustive variants as `TyErr`.
|
|
||||||
(_, true, true) => cx.tcx.types.err,
|
|
||||||
// Treat all non-visible fields as `TyErr`. They can't appear in any
|
|
||||||
// other pattern from this match (because they are private), so their
|
|
||||||
// type does not matter - but we don't want to know they are
|
|
||||||
// uninhabited.
|
|
||||||
(false, ..) => cx.tcx.types.err,
|
|
||||||
(true, ..) => {
|
|
||||||
let ty = field.ty(cx.tcx, substs);
|
|
||||||
match ty.kind {
|
|
||||||
// If the field type returned is an array of an unknown size
|
|
||||||
// return an TyErr.
|
|
||||||
ty::Array(_, len)
|
|
||||||
if len.try_eval_usize(cx.tcx, cx.param_env).is_none() =>
|
|
||||||
{
|
|
||||||
cx.tcx.types.err
|
|
||||||
}
|
|
||||||
_ => ty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
|
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
|
||||||
// meaning all other types will compare unequal and thus equal patterns often do not cause the
|
// meaning all other types will compare unequal and thus equal patterns often do not cause the
|
||||||
// second pattern to lint about unreachable match arms.
|
// second pattern to lint about unreachable match arms.
|
||||||
@ -1900,21 +1879,22 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
|
|||||||
///
|
///
|
||||||
/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
|
/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
|
||||||
/// ranges that case.
|
/// ranges that case.
|
||||||
|
///
|
||||||
|
/// This also splits variable-length slices into fixed-length slices.
|
||||||
fn split_grouped_constructors<'p, 'tcx>(
|
fn split_grouped_constructors<'p, 'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
pcx: PatCtxt<'tcx>,
|
||||||
ctors: Vec<Constructor<'tcx>>,
|
ctors: Vec<Constructor<'tcx>>,
|
||||||
matrix: &Matrix<'p, 'tcx>,
|
matrix: &Matrix<'p, 'tcx>,
|
||||||
ty: Ty<'tcx>,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
hir_id: Option<HirId>,
|
hir_id: Option<HirId>,
|
||||||
) -> Vec<Constructor<'tcx>> {
|
) -> Vec<Constructor<'tcx>> {
|
||||||
|
let ty = pcx.ty;
|
||||||
let mut split_ctors = Vec::with_capacity(ctors.len());
|
let mut split_ctors = Vec::with_capacity(ctors.len());
|
||||||
|
|
||||||
for ctor in ctors.into_iter() {
|
for ctor in ctors.into_iter() {
|
||||||
match ctor {
|
match ctor {
|
||||||
// For now, only ranges may denote groups of "subconstructors", so we only need to
|
|
||||||
// special-case constant ranges.
|
|
||||||
ConstantRange(..) if should_treat_range_exhaustively(tcx, &ctor) => {
|
ConstantRange(..) if should_treat_range_exhaustively(tcx, &ctor) => {
|
||||||
// We only care about finding all the subranges within the range of the constructor
|
// We only care about finding all the subranges within the range of the constructor
|
||||||
// range. Anything else is irrelevant, because it is guaranteed to result in
|
// range. Anything else is irrelevant, because it is guaranteed to result in
|
||||||
@ -1996,6 +1976,121 @@ fn split_grouped_constructors<'p, 'tcx>(
|
|||||||
split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span));
|
split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VarLenSlice(self_prefix, self_suffix) => {
|
||||||
|
// The exhaustiveness-checking paper does not include any details on
|
||||||
|
// checking variable-length slice patterns. However, they are matched
|
||||||
|
// by an infinite collection of fixed-length array patterns.
|
||||||
|
//
|
||||||
|
// Checking the infinite set directly would take an infinite amount
|
||||||
|
// of time. However, it turns out that for each finite set of
|
||||||
|
// patterns `P`, all sufficiently large array lengths are equivalent:
|
||||||
|
//
|
||||||
|
// Each slice `s` with a "sufficiently-large" length `l ≥ L` that applies
|
||||||
|
// to exactly the subset `Pₜ` of `P` can be transformed to a slice
|
||||||
|
// `sₘ` for each sufficiently-large length `m` that applies to exactly
|
||||||
|
// the same subset of `P`.
|
||||||
|
//
|
||||||
|
// Because of that, each witness for reachability-checking from one
|
||||||
|
// of the sufficiently-large lengths can be transformed to an
|
||||||
|
// equally-valid witness from any other length, so we only have
|
||||||
|
// to check slice lengths from the "minimal sufficiently-large length"
|
||||||
|
// and below.
|
||||||
|
//
|
||||||
|
// Note that the fact that there is a *single* `sₘ` for each `m`
|
||||||
|
// not depending on the specific pattern in `P` is important: if
|
||||||
|
// you look at the pair of patterns
|
||||||
|
// `[true, ..]`
|
||||||
|
// `[.., false]`
|
||||||
|
// Then any slice of length ≥1 that matches one of these two
|
||||||
|
// patterns can be trivially turned to a slice of any
|
||||||
|
// other length ≥1 that matches them and vice-versa - for
|
||||||
|
// but the slice from length 2 `[false, true]` that matches neither
|
||||||
|
// of these patterns can't be turned to a slice from length 1 that
|
||||||
|
// matches neither of these patterns, so we have to consider
|
||||||
|
// slices from length 2 there.
|
||||||
|
//
|
||||||
|
// Now, to see that that length exists and find it, observe that slice
|
||||||
|
// patterns are either "fixed-length" patterns (`[_, _, _]`) or
|
||||||
|
// "variable-length" patterns (`[_, .., _]`).
|
||||||
|
//
|
||||||
|
// For fixed-length patterns, all slices with lengths *longer* than
|
||||||
|
// the pattern's length have the same outcome (of not matching), so
|
||||||
|
// as long as `L` is greater than the pattern's length we can pick
|
||||||
|
// any `sₘ` from that length and get the same result.
|
||||||
|
//
|
||||||
|
// For variable-length patterns, the situation is more complicated,
|
||||||
|
// because as seen above the precise value of `sₘ` matters.
|
||||||
|
//
|
||||||
|
// However, for each variable-length pattern `p` with a prefix of length
|
||||||
|
// `plₚ` and suffix of length `slₚ`, only the first `plₚ` and the last
|
||||||
|
// `slₚ` elements are examined.
|
||||||
|
//
|
||||||
|
// Therefore, as long as `L` is positive (to avoid concerns about empty
|
||||||
|
// types), all elements after the maximum prefix length and before
|
||||||
|
// the maximum suffix length are not examined by any variable-length
|
||||||
|
// pattern, and therefore can be added/removed without affecting
|
||||||
|
// them - creating equivalent patterns from any sufficiently-large
|
||||||
|
// length.
|
||||||
|
//
|
||||||
|
// Of course, if fixed-length patterns exist, we must be sure
|
||||||
|
// that our length is large enough to miss them all, so
|
||||||
|
// we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`
|
||||||
|
//
|
||||||
|
// for example, with the above pair of patterns, all elements
|
||||||
|
// but the first and last can be added/removed, so any
|
||||||
|
// witness of length ≥2 (say, `[false, false, true]`) can be
|
||||||
|
// turned to a witness from any other length ≥2.
|
||||||
|
|
||||||
|
let mut max_prefix_len = self_prefix;
|
||||||
|
let mut max_suffix_len = self_suffix;
|
||||||
|
let mut max_fixed_len = 0;
|
||||||
|
|
||||||
|
for row in matrix.heads() {
|
||||||
|
match *row.kind {
|
||||||
|
PatKind::Constant { value } => {
|
||||||
|
// extract the length of an array/slice from a constant
|
||||||
|
match (value.val, &value.ty.kind) {
|
||||||
|
(_, ty::Array(_, n)) => {
|
||||||
|
max_fixed_len =
|
||||||
|
cmp::max(max_fixed_len, n.eval_usize(tcx, param_env))
|
||||||
|
}
|
||||||
|
(ConstValue::Slice { start, end, .. }, ty::Slice(_)) => {
|
||||||
|
max_fixed_len = cmp::max(max_fixed_len, (end - start) as u64)
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PatKind::Slice { ref prefix, slice: None, ref suffix } => {
|
||||||
|
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
|
||||||
|
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
|
||||||
|
}
|
||||||
|
PatKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
|
||||||
|
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
|
||||||
|
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For diagnostics, we keep the prefix and suffix lengths separate, so in the case
|
||||||
|
// where `max_fixed_len + 1` is the largest, we adapt `max_prefix_len` accordingly,
|
||||||
|
// so that `L = max_prefix_len + max_suffix_len`.
|
||||||
|
if max_fixed_len + 1 >= max_prefix_len + max_suffix_len {
|
||||||
|
// The subtraction can't overflow thanks to the above check.
|
||||||
|
// The new `max_prefix_len` is also guaranteed to be larger than its previous
|
||||||
|
// value.
|
||||||
|
max_prefix_len = max_fixed_len + 1 - max_suffix_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// `ctor` originally covered the range `(self_prefix + self_suffix..infinity)`. We
|
||||||
|
// now split it into two: lengths smaller than `max_prefix_len + max_suffix_len`
|
||||||
|
// are treated independently as fixed-lengths slices, and lengths above are
|
||||||
|
// captured by a final VarLenSlice constructor.
|
||||||
|
split_ctors.extend(
|
||||||
|
(self_prefix + self_suffix..max_prefix_len + max_suffix_len).map(FixedLenSlice),
|
||||||
|
);
|
||||||
|
split_ctors.push(VarLenSlice(max_prefix_len, max_suffix_len));
|
||||||
|
}
|
||||||
// Any other constructor can be used unchanged.
|
// Any other constructor can be used unchanged.
|
||||||
_ => split_ctors.push(ctor),
|
_ => split_ctors.push(ctor),
|
||||||
}
|
}
|
||||||
@ -2238,7 +2333,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
|
|||||||
|
|
||||||
PatKind::Array { ref prefix, ref slice, ref suffix }
|
PatKind::Array { ref prefix, ref slice, ref suffix }
|
||||||
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
|
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
|
||||||
Slice(..) => {
|
FixedLenSlice(..) | VarLenSlice(..) => {
|
||||||
let pat_len = prefix.len() + suffix.len();
|
let pat_len = prefix.len() + suffix.len();
|
||||||
if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
|
if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
|
||||||
if slice_count == 0 || slice.is_some() {
|
if slice_count == 0 || slice.is_some() {
|
||||||
|
@ -18,7 +18,7 @@ use rustc::hir::{self, Pat};
|
|||||||
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
|
use syntax_pos::{MultiSpan, Span};
|
||||||
|
|
||||||
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
|
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||||
let body_id = match tcx.hir().as_local_hir_id(def_id) {
|
let body_id = match tcx.hir().as_local_hir_id(def_id) {
|
||||||
@ -491,7 +491,7 @@ fn check_not_useful(
|
|||||||
matrix: &Matrix<'_, 'tcx>,
|
matrix: &Matrix<'_, 'tcx>,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
) -> Result<(), Vec<super::Pat<'tcx>>> {
|
) -> Result<(), Vec<super::Pat<'tcx>>> {
|
||||||
let wild_pattern = super::Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
|
let wild_pattern = super::Pat::wildcard_from_ty(ty);
|
||||||
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
|
match is_useful(cx, matrix, &PatStack::from_pattern(&wild_pattern), ConstructWitness, hir_id) {
|
||||||
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
|
NotUseful => Ok(()), // This is good, wildcard pattern isn't reachable.
|
||||||
UsefulWithWitness(pats) => Err(if pats.is_empty() {
|
UsefulWithWitness(pats) => Err(if pats.is_empty() {
|
||||||
|
@ -26,7 +26,7 @@ use rustc_index::vec::Idx;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum PatternError {
|
pub enum PatternError {
|
||||||
@ -55,6 +55,11 @@ pub struct Pat<'tcx> {
|
|||||||
pub kind: Box<PatKind<'tcx>>,
|
pub kind: Box<PatKind<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Pat<'tcx> {
|
||||||
|
pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
|
||||||
|
Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct PatTyProj<'tcx> {
|
pub struct PatTyProj<'tcx> {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _]` not covered
|
error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
|
||||||
--> $DIR/const_let_refutable.rs:3:16
|
--> $DIR/const_let_refutable.rs:3:16
|
||||||
|
|
|
|
||||||
LL | const fn slice([a, b]: &[i32]) -> i32 {
|
LL | const fn slice([a, b]: &[i32]) -> i32 {
|
||||||
| ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _]` not covered
|
| ^^^^^^ patterns `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
|
||||||
|
|
||||||
error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
|
error[E0723]: can only call other `const fn` within a `const fn`, but `const <&i32 as std::ops::Add>::add` is not stable as `const fn`
|
||||||
--> $DIR/const_let_refutable.rs:4:5
|
--> $DIR/const_let_refutable.rs:4:5
|
||||||
|
@ -6,11 +6,11 @@ LL | match buf {
|
|||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
|
error[E0004]: non-exhaustive patterns: `&[..]` not covered
|
||||||
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
--> $DIR/match-byte-array-patterns-2.rs:10:11
|
||||||
|
|
|
|
||||||
LL | match buf {
|
LL | match buf {
|
||||||
| ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 3 more not covered
|
| ^^^ pattern `&[..]` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
fn check(list: &[Option<()>]) {
|
fn check(list: &[Option<()>]) {
|
||||||
match list {
|
match list {
|
||||||
//~^ ERROR `&[_, Some(_), None, _]` not covered
|
//~^ ERROR `&[_, Some(_), .., None, _]` not covered
|
||||||
&[] => {},
|
&[] => {},
|
||||||
&[_] => {},
|
&[_] => {},
|
||||||
&[_, _] => {},
|
&[_, _] => {},
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error[E0004]: non-exhaustive patterns: `&[_, Some(_), None, _]` not covered
|
error[E0004]: non-exhaustive patterns: `&[_, Some(_), .., None, _]` not covered
|
||||||
--> $DIR/match-slice-patterns.rs:4:11
|
--> $DIR/match-slice-patterns.rs:4:11
|
||||||
|
|
|
|
||||||
LL | match list {
|
LL | match list {
|
||||||
| ^^^^ pattern `&[_, Some(_), None, _]` not covered
|
| ^^^^ pattern `&[_, Some(_), .., None, _]` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
let vec = vec![0.5f32];
|
let vec = vec![0.5f32];
|
||||||
let vec: &[f32] = &vec;
|
let vec: &[f32] = &vec;
|
||||||
match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _]` not covered
|
match *vec { //~ ERROR non-exhaustive patterns: `[_, _, _, _, ..]` not covered
|
||||||
[0.1, 0.2, 0.3] => (),
|
[0.1, 0.2, 0.3] => (),
|
||||||
[0.1, 0.2] => (),
|
[0.1, 0.2] => (),
|
||||||
[0.1] => (),
|
[0.1] => (),
|
||||||
|
@ -66,11 +66,11 @@ LL | match *vec {
|
|||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `[_, _, _, _]` not covered
|
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
|
||||||
--> $DIR/non-exhaustive-match.rs:47:11
|
--> $DIR/non-exhaustive-match.rs:47:11
|
||||||
|
|
|
|
||||||
LL | match *vec {
|
LL | match *vec {
|
||||||
| ^^^^ pattern `[_, _, _, _]` not covered
|
| ^^^^ pattern `[_, _, _, _, ..]` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
#![feature(slice_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s: &[bool] = &[true; 0];
|
||||||
|
let s1: &[bool; 1] = &[false; 1];
|
||||||
|
let s2: &[bool; 2] = &[false; 2];
|
||||||
|
let s3: &[bool; 3] = &[false; 3];
|
||||||
|
|
||||||
|
match s1 {
|
||||||
|
[true, ..] => {}
|
||||||
|
[.., false] => {}
|
||||||
|
}
|
||||||
|
match s2 {
|
||||||
|
//~^ ERROR `&[false, true]` not covered
|
||||||
|
[true, ..] => {}
|
||||||
|
[.., false] => {}
|
||||||
|
}
|
||||||
|
match s3 {
|
||||||
|
//~^ ERROR `&[false, _, true]` not covered
|
||||||
|
[true, ..] => {}
|
||||||
|
[.., false] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[false, .., true]` not covered
|
||||||
|
[] => {}
|
||||||
|
[true, ..] => {}
|
||||||
|
[.., false] => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match s3 {
|
||||||
|
//~^ ERROR `&[false, _, _]` not covered
|
||||||
|
[true, .., true] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[_, ..]` not covered
|
||||||
|
[] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[_, _, ..]` not covered
|
||||||
|
[] => {}
|
||||||
|
[_] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[false, ..]` not covered
|
||||||
|
[] => {}
|
||||||
|
[true, ..] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[false, _, ..]` not covered
|
||||||
|
[] => {}
|
||||||
|
[_] => {}
|
||||||
|
[true, ..] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[_, .., false]` not covered
|
||||||
|
[] => {}
|
||||||
|
[_] => {}
|
||||||
|
[.., true] => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[_, _, .., true]` not covered
|
||||||
|
[] => {}
|
||||||
|
[_] => {}
|
||||||
|
[_, _] => {}
|
||||||
|
[.., false] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
//~^ ERROR `&[true, _, .., _]` not covered
|
||||||
|
[] => {}
|
||||||
|
[_] => {}
|
||||||
|
[_, _] => {}
|
||||||
|
[false, .., false] => {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
error[E0004]: non-exhaustive patterns: `&[false, true]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:13:11
|
||||||
|
|
|
||||||
|
LL | match s2 {
|
||||||
|
| ^^ pattern `&[false, true]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[false, _, true]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:18:11
|
||||||
|
|
|
||||||
|
LL | match s3 {
|
||||||
|
| ^^ pattern `&[false, _, true]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[false, .., true]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:23:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[false, .., true]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[false, _, _]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:30:11
|
||||||
|
|
|
||||||
|
LL | match s3 {
|
||||||
|
| ^^ pattern `&[false, _, _]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:34:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[_, ..]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:38:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[_, _, ..]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:43:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[false, ..]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:48:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[false, _, ..]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:54:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[_, .., false]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:61:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[_, _, .., true]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered
|
||||||
|
--> $DIR/slice-patterns-exhaustiveness.rs:68:11
|
||||||
|
|
|
||||||
|
LL | match s {
|
||||||
|
| ^ pattern `&[true, _, .., _]` not covered
|
||||||
|
|
|
||||||
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0004`.
|
27
src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs
Normal file
27
src/test/ui/pattern/usefulness/slice-patterns-irrefutable.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// check-pass
|
||||||
|
#![feature(slice_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s: &[bool] = &[true; 0];
|
||||||
|
let s0: &[bool; 0] = &[];
|
||||||
|
let s1: &[bool; 1] = &[false; 1];
|
||||||
|
let s2: &[bool; 2] = &[false; 2];
|
||||||
|
|
||||||
|
let [] = s0;
|
||||||
|
let [_] = s1;
|
||||||
|
let [_, _] = s2;
|
||||||
|
|
||||||
|
let [..] = s;
|
||||||
|
let [..] = s0;
|
||||||
|
let [..] = s1;
|
||||||
|
let [..] = s2;
|
||||||
|
|
||||||
|
let [_, ..] = s1;
|
||||||
|
let [.., _] = s1;
|
||||||
|
let [_, ..] = s2;
|
||||||
|
let [.., _] = s2;
|
||||||
|
|
||||||
|
let [_, _, ..] = s2;
|
||||||
|
let [_, .., _] = s2;
|
||||||
|
let [.., _, _] = s2;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
#![feature(slice_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s: &[bool] = &[true; 0];
|
||||||
|
|
||||||
|
match s {
|
||||||
|
[true, ..] => {}
|
||||||
|
[true, ..] => {} //~ ERROR unreachable pattern
|
||||||
|
[true] => {} //~ ERROR unreachable pattern
|
||||||
|
[..] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
[.., true] => {}
|
||||||
|
[.., true] => {} //~ ERROR unreachable pattern
|
||||||
|
[true] => {} //~ ERROR unreachable pattern
|
||||||
|
[..] => {}
|
||||||
|
}
|
||||||
|
match s {
|
||||||
|
[false, .., true] => {}
|
||||||
|
[false, .., true] => {} //~ ERROR unreachable pattern
|
||||||
|
[false, true] => {} //~ ERROR unreachable pattern
|
||||||
|
[false] => {}
|
||||||
|
[..] => {}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:9:9
|
||||||
|
|
|
||||||
|
LL | [true, ..] => {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: lint level defined here
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unreachable_patterns)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:10:9
|
||||||
|
|
|
||||||
|
LL | [true] => {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:15:9
|
||||||
|
|
|
||||||
|
LL | [.., true] => {}
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:16:9
|
||||||
|
|
|
||||||
|
LL | [true] => {}
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:21:9
|
||||||
|
|
|
||||||
|
LL | [false, .., true] => {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice-patterns-reachability.rs:22:9
|
||||||
|
|
|
||||||
|
LL | [false, true] => {}
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
@ -30,11 +30,11 @@ LL | let _ = match x {};
|
|||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
error[E0004]: non-exhaustive patterns: `&[_]` not covered
|
error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered
|
||||||
--> $DIR/uninhabited-matches-feature-gated.rs:21:19
|
--> $DIR/uninhabited-matches-feature-gated.rs:21:19
|
||||||
|
|
|
|
||||||
LL | let _ = match x {
|
LL | let _ = match x {
|
||||||
| ^ pattern `&[_]` not covered
|
| ^ pattern `&[_, ..]` not covered
|
||||||
|
|
|
|
||||||
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user