Fix handling slices of empty types
This commit is contained in:
parent
edf6a2d337
commit
c1b29b338d
@ -859,6 +859,7 @@ impl<'tcx> Constructor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the set of all constructors for a type.
|
/// Describes the set of all constructors for a type.
|
||||||
|
#[derive(Debug)]
|
||||||
pub(super) enum ConstructorSet {
|
pub(super) enum ConstructorSet {
|
||||||
/// The type has a single constructor, e.g. `&T` or a struct.
|
/// The type has a single constructor, e.g. `&T` or a struct.
|
||||||
Single,
|
Single,
|
||||||
@ -903,6 +904,7 @@ pub(super) enum ConstructorSet {
|
|||||||
/// - constructors in `present` and `missing` are split for the column; in other words, they are
|
/// - constructors in `present` and `missing` are split for the column; in other words, they are
|
||||||
/// either fully included in or disjoint from each constructor in the column. This avoids
|
/// either fully included in or disjoint from each constructor in the column. This avoids
|
||||||
/// non-trivial intersections like between `0..10` and `5..15`.
|
/// non-trivial intersections like between `0..10` and `5..15`.
|
||||||
|
#[derive(Debug)]
|
||||||
struct SplitConstructorSet<'tcx> {
|
struct SplitConstructorSet<'tcx> {
|
||||||
present: SmallVec<[Constructor<'tcx>; 1]>,
|
present: SmallVec<[Constructor<'tcx>; 1]>,
|
||||||
missing: Vec<Constructor<'tcx>>,
|
missing: Vec<Constructor<'tcx>>,
|
||||||
@ -911,8 +913,8 @@ struct SplitConstructorSet<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructorSet {
|
impl ConstructorSet {
|
||||||
|
#[instrument(level = "debug", skip(cx), ret)]
|
||||||
pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
|
pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
|
||||||
debug!("ConstructorSet::for_ty({:?})", ty);
|
|
||||||
let make_range =
|
let make_range =
|
||||||
|start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included);
|
|start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included);
|
||||||
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
// This determines the set of all possible constructors for the type `ty`. For numbers,
|
||||||
@ -1036,6 +1038,7 @@ impl ConstructorSet {
|
|||||||
/// This is the core logical operation of exhaustiveness checking. This analyzes a column a
|
/// This is the core logical operation of exhaustiveness checking. This analyzes a column a
|
||||||
/// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split
|
/// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split
|
||||||
/// constructors to handle non-trivial intersections e.g. on ranges or slices.
|
/// constructors to handle non-trivial intersections e.g. on ranges or slices.
|
||||||
|
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
|
||||||
fn split<'a, 'tcx>(
|
fn split<'a, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
pcx: &PatCtxt<'_, '_, 'tcx>,
|
pcx: &PatCtxt<'_, '_, 'tcx>,
|
||||||
@ -1111,7 +1114,7 @@ impl ConstructorSet {
|
|||||||
}
|
}
|
||||||
&ConstructorSet::Slice(array_len) => {
|
&ConstructorSet::Slice(array_len) => {
|
||||||
let seen_slices = seen.map(|c| c.as_slice().unwrap());
|
let seen_slices = seen.map(|c| c.as_slice().unwrap());
|
||||||
let base_slice = Slice { kind: VarLen(0, 0), array_len };
|
let base_slice = Slice::new(array_len, VarLen(0, 0));
|
||||||
for (seen, splitted_slice) in base_slice.split(seen_slices) {
|
for (seen, splitted_slice) in base_slice.split(seen_slices) {
|
||||||
let ctor = Slice(splitted_slice);
|
let ctor = Slice(splitted_slice);
|
||||||
match seen {
|
match seen {
|
||||||
@ -1121,12 +1124,22 @@ impl ConstructorSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstructorSet::SliceOfEmpty => {
|
ConstructorSet::SliceOfEmpty => {
|
||||||
// Behaves essentially like `Single`.
|
// This one is tricky because even though there's only one possible value of this
|
||||||
let slice = Slice(Slice::new(None, FixedLen(0)));
|
// type (namely `[]`), slice patterns of all lengths are allowed, they're just
|
||||||
if seen.next().is_none() {
|
// unreachable if length != 0.
|
||||||
missing.push(slice);
|
// We still gather the seen constructors in `present`, but the only slice that can
|
||||||
} else {
|
// go in `missing` is `[]`.
|
||||||
present.push(slice);
|
let seen_slices = seen.map(|c| c.as_slice().unwrap());
|
||||||
|
let base_slice = Slice::new(None, VarLen(0, 0));
|
||||||
|
for (seen, splitted_slice) in base_slice.split(seen_slices) {
|
||||||
|
let ctor = Slice(splitted_slice);
|
||||||
|
match seen {
|
||||||
|
Presence::Seen => present.push(ctor),
|
||||||
|
Presence::Unseen if splitted_slice.arity() == 0 => {
|
||||||
|
missing.push(Slice(Slice::new(None, FixedLen(0))))
|
||||||
|
}
|
||||||
|
Presence::Unseen => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstructorSet::Unlistable => {
|
ConstructorSet::Unlistable => {
|
||||||
|
22
tests/ui/pattern/usefulness/slice_of_empty.rs
Normal file
22
tests/ui/pattern/usefulness/slice_of_empty.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#![feature(never_type)]
|
||||||
|
#![feature(exhaustive_patterns)]
|
||||||
|
#![deny(unreachable_patterns)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn foo(nevers: &[!]) {
|
||||||
|
match nevers {
|
||||||
|
&[] => (),
|
||||||
|
};
|
||||||
|
|
||||||
|
match nevers {
|
||||||
|
&[] => (),
|
||||||
|
&[_] => (), //~ ERROR unreachable pattern
|
||||||
|
&[_, _, ..] => (), //~ ERROR unreachable pattern
|
||||||
|
};
|
||||||
|
|
||||||
|
match nevers {
|
||||||
|
//~^ ERROR non-exhaustive patterns: `&[]` not covered
|
||||||
|
&[_] => (), //~ ERROR unreachable pattern
|
||||||
|
};
|
||||||
|
}
|
39
tests/ui/pattern/usefulness/slice_of_empty.stderr
Normal file
39
tests/ui/pattern/usefulness/slice_of_empty.stderr
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice_of_empty.rs:14:9
|
||||||
|
|
|
||||||
|
LL | &[_] => (),
|
||||||
|
| ^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/slice_of_empty.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(unreachable_patterns)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice_of_empty.rs:15:9
|
||||||
|
|
|
||||||
|
LL | &[_, _, ..] => (),
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: unreachable pattern
|
||||||
|
--> $DIR/slice_of_empty.rs:20:9
|
||||||
|
|
|
||||||
|
LL | &[_] => (),
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
|
error[E0004]: non-exhaustive patterns: `&[]` not covered
|
||||||
|
--> $DIR/slice_of_empty.rs:18:11
|
||||||
|
|
|
||||||
|
LL | match nevers {
|
||||||
|
| ^^^^^^ pattern `&[]` not covered
|
||||||
|
|
|
||||||
|
= note: the matched value is of type `&[!]`
|
||||||
|
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||||
|
|
|
||||||
|
LL | &[_] => (), &[] => todo!(),
|
||||||
|
| ++++++++++++++++
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0004`.
|
Loading…
x
Reference in New Issue
Block a user