Skip to content

Commit e092a17

Browse files
committed
Add special variable-length slice constructor
1 parent d2b7711 commit e092a17

File tree

1 file changed

+72
-26
lines changed

1 file changed

+72
-26
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 72 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ enum Constructor<'tcx> {
588588
ConstantRange(u128, u128, Ty<'tcx>, RangeEnd, Span),
589589
/// Array patterns of length n.
590590
FixedLenSlice(u64),
591+
/// Slice patterns. Stands for any array constructor of length >= n.
592+
VarLenSlice(u64),
591593
}
592594

593595
// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
@@ -602,6 +604,7 @@ impl<'tcx> std::cmp::PartialEq for Constructor<'tcx> {
602604
Constructor::ConstantRange(b_start, b_end, b_ty, b_range_end, _),
603605
) => a_start == b_start && a_end == b_end && a_ty == b_ty && a_range_end == b_range_end,
604606
(Constructor::FixedLenSlice(a), Constructor::FixedLenSlice(b)) => a == b,
607+
(Constructor::VarLenSlice(a), Constructor::VarLenSlice(b)) => a == b,
605608
_ => false,
606609
}
607610
}
@@ -611,6 +614,7 @@ impl<'tcx> Constructor<'tcx> {
611614
fn is_slice(&self) -> bool {
612615
match self {
613616
FixedLenSlice { .. } => true,
617+
VarLenSlice { .. } => true,
614618
_ => false,
615619
}
616620
}
@@ -645,6 +649,7 @@ impl<'tcx> Constructor<'tcx> {
645649
)
646650
}
647651
Constructor::FixedLenSlice(val) => format!("[{}]", val),
652+
Constructor::VarLenSlice(val) => format!("[{}, ..]", val),
648653
_ => bug!("bad constructor being displayed: `{:?}", self),
649654
}
650655
}
@@ -653,19 +658,59 @@ impl<'tcx> Constructor<'tcx> {
653658
// anything in `other_ctors`.
654659
fn subtract_ctors(
655660
&self,
661+
pcx: PatCtxt<'tcx>,
656662
tcx: TyCtxt<'tcx>,
657663
param_env: ty::ParamEnv<'tcx>,
658664
other_ctors: &Vec<Constructor<'tcx>>,
659665
) -> Vec<Constructor<'tcx>> {
660666
match self {
661667
// Those constructors can only match themselves.
662-
Single | Variant(_) | FixedLenSlice(_) => {
668+
Single | Variant(_) => {
663669
if other_ctors.iter().any(|c| c == self) {
664670
vec![]
665671
} else {
666672
vec![self.clone()]
667673
}
668674
}
675+
FixedLenSlice(_) | VarLenSlice(_) => {
676+
let mut remaining_ctors = if let VarLenSlice(len) = self {
677+
(*len..pcx.max_slice_length + 1).map(FixedLenSlice).collect()
678+
} else {
679+
vec![self.clone()]
680+
};
681+
682+
// For each used ctor, subtract from the current set of constructors.
683+
// Naming: we remove the "neg" constructors from the "pos" ones.
684+
// Remember, VarLenSlice(n) covers the union of FixedLenSlice from
685+
// n to infinity.
686+
for neg_ctor in other_ctors {
687+
remaining_ctors = remaining_ctors
688+
.into_iter()
689+
.flat_map(|pos_ctor| -> SmallVec<[Constructor<'tcx>; 1]> {
690+
// Compute pos_ctor \ neg_ctor
691+
match (&pos_ctor, neg_ctor) {
692+
(FixedLenSlice(pos_len), VarLenSlice(neg_len)) => {
693+
if neg_len <= pos_len {
694+
smallvec![]
695+
} else {
696+
smallvec![pos_ctor]
697+
}
698+
}
699+
_ if pos_ctor == *neg_ctor => smallvec![],
700+
_ => smallvec![pos_ctor],
701+
}
702+
})
703+
.collect();
704+
705+
// If the constructors that have been considered so far already cover
706+
// the entire range of `self`, no need to look at more constructors.
707+
if remaining_ctors.is_empty() {
708+
break;
709+
}
710+
}
711+
712+
remaining_ctors
713+
}
669714
ConstantRange(..) | ConstantValue(..) => {
670715
let mut remaining_ctors = vec![self.clone()];
671716
for other_ctor in other_ctors {
@@ -719,7 +764,7 @@ impl<'tcx> Constructor<'tcx> {
719764
match ty.kind {
720765
ty::Tuple(ref fs) => fs.len() as u64,
721766
ty::Slice(..) | ty::Array(..) => match *self {
722-
FixedLenSlice(length) => length,
767+
FixedLenSlice(length) | VarLenSlice(length) => length,
723768
ConstantValue(..) => 0,
724769
_ => bug!("bad slice pattern {:?} {:?}", self, ty),
725770
},
@@ -999,7 +1044,7 @@ fn all_constructors<'a, 'tcx>(
9991044
if cx.is_uninhabited(sub_ty) {
10001045
vec![FixedLenSlice(0)]
10011046
} else {
1002-
(0..pcx.max_slice_length + 1).map(|length| FixedLenSlice(length)).collect()
1047+
vec![VarLenSlice(0)]
10031048
}
10041049
}
10051050
ty::Adt(def, substs) if def.is_enum() => def
@@ -1403,6 +1448,7 @@ impl<'tcx> IntRange<'tcx> {
14031448

14041449
// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
14051450
struct MissingConstructors<'tcx> {
1451+
pcx: PatCtxt<'tcx>,
14061452
tcx: TyCtxt<'tcx>,
14071453
param_env: ty::ParamEnv<'tcx>,
14081454
all_ctors: Vec<Constructor<'tcx>>,
@@ -1411,12 +1457,13 @@ struct MissingConstructors<'tcx> {
14111457

14121458
impl<'tcx> MissingConstructors<'tcx> {
14131459
fn new(
1460+
pcx: PatCtxt<'tcx>,
14141461
tcx: TyCtxt<'tcx>,
14151462
param_env: ty::ParamEnv<'tcx>,
14161463
all_ctors: Vec<Constructor<'tcx>>,
14171464
used_ctors: Vec<Constructor<'tcx>>,
14181465
) -> Self {
1419-
MissingConstructors { tcx, param_env, all_ctors, used_ctors }
1466+
MissingConstructors { pcx, tcx, param_env, all_ctors, used_ctors }
14201467
}
14211468

14221469
fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
@@ -1435,7 +1482,7 @@ impl<'tcx> MissingConstructors<'tcx> {
14351482
/// Iterate over all_ctors \ used_ctors
14361483
fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
14371484
self.all_ctors.iter().flat_map(move |req_ctor| {
1438-
req_ctor.subtract_ctors(self.tcx, self.param_env, &self.used_ctors)
1485+
req_ctor.subtract_ctors(self.pcx, self.tcx, self.param_env, &self.used_ctors)
14391486
})
14401487
}
14411488
}
@@ -1531,9 +1578,9 @@ pub fn is_useful<'p, 'a, 'tcx>(
15311578
split_grouped_constructors(
15321579
cx.tcx,
15331580
cx.param_env,
1581+
pcx,
15341582
constructors,
15351583
matrix,
1536-
pcx.ty,
15371584
pcx.span,
15381585
Some(hir_id),
15391586
)
@@ -1578,7 +1625,8 @@ pub fn is_useful<'p, 'a, 'tcx>(
15781625
// non-wildcard patterns in the current column. To determine if
15791626
// the set is empty, we can check that `.peek().is_none()`, so
15801627
// we only fully construct them on-demand, because they're rarely used and can be big.
1581-
let missing_ctors = MissingConstructors::new(cx.tcx, cx.param_env, all_ctors, used_ctors);
1628+
let missing_ctors =
1629+
MissingConstructors::new(pcx, cx.tcx, cx.param_env, all_ctors, used_ctors);
15821630

15831631
debug!(
15841632
"missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
@@ -1595,19 +1643,13 @@ pub fn is_useful<'p, 'a, 'tcx>(
15951643

15961644
if missing_ctors.is_empty() && !is_non_exhaustive {
15971645
let (all_ctors, _) = missing_ctors.into_inner();
1598-
split_grouped_constructors(
1599-
cx.tcx,
1600-
cx.param_env,
1601-
all_ctors,
1602-
matrix,
1603-
pcx.ty,
1604-
DUMMY_SP,
1605-
None,
1606-
)
1607-
.into_iter()
1608-
.map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
1609-
.find(|result| result.is_useful())
1610-
.unwrap_or(NotUseful)
1646+
split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
1647+
.into_iter()
1648+
.map(|c| {
1649+
is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id)
1650+
})
1651+
.find(|result| result.is_useful())
1652+
.unwrap_or(NotUseful)
16111653
} else {
16121654
let matrix = matrix.specialize_wildcard();
16131655
let v = v.to_tail();
@@ -1731,7 +1773,7 @@ fn pat_constructors<'tcx>(
17311773
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
17321774
let pat_len = prefix.len() as u64 + suffix.len() as u64;
17331775
if slice.is_some() {
1734-
Some((pat_len..pcx.max_slice_length + 1).map(FixedLenSlice).collect())
1776+
Some(vec![VarLenSlice(pat_len)])
17351777
} else {
17361778
Some(vec![FixedLenSlice(pat_len)])
17371779
}
@@ -1755,7 +1797,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx>(
17551797
match ty.kind {
17561798
ty::Tuple(ref fs) => fs.into_iter().map(|t| t.expect_ty()).collect(),
17571799
ty::Slice(ty) | ty::Array(ty, _) => match *ctor {
1758-
FixedLenSlice(length) => (0..length).map(|_| ty).collect(),
1800+
FixedLenSlice(length) | VarLenSlice(length) => (0..length).map(|_| ty).collect(),
17591801
ConstantValue(..) => vec![],
17601802
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty),
17611803
},
@@ -1914,21 +1956,22 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'tcx>, ctor: &Constructor<'tcx>)
19141956
///
19151957
/// `hir_id` is `None` when we're evaluating the wildcard pattern, do not lint for overlapping in
19161958
/// ranges that case.
1959+
///
1960+
/// This also splits variable-length slices into fixed-length slices.
19171961
fn split_grouped_constructors<'p, 'tcx>(
19181962
tcx: TyCtxt<'tcx>,
19191963
param_env: ty::ParamEnv<'tcx>,
1964+
pcx: PatCtxt<'tcx>,
19201965
ctors: Vec<Constructor<'tcx>>,
19211966
matrix: &Matrix<'p, 'tcx>,
1922-
ty: Ty<'tcx>,
19231967
span: Span,
19241968
hir_id: Option<HirId>,
19251969
) -> Vec<Constructor<'tcx>> {
1970+
let ty = pcx.ty;
19261971
let mut split_ctors = Vec::with_capacity(ctors.len());
19271972

19281973
for ctor in ctors.into_iter() {
19291974
match ctor {
1930-
// For now, only ranges may denote groups of "subconstructors", so we only need to
1931-
// special-case constant ranges.
19321975
ConstantRange(..) if should_treat_range_exhaustively(tcx, &ctor) => {
19331976
// We only care about finding all the subranges within the range of the constructor
19341977
// range. Anything else is irrelevant, because it is guaranteed to result in
@@ -2010,6 +2053,9 @@ fn split_grouped_constructors<'p, 'tcx>(
20102053
split_ctors.push(IntRange::range_to_ctor(tcx, ty, range, span));
20112054
}
20122055
}
2056+
VarLenSlice(len) => {
2057+
split_ctors.extend((len..pcx.max_slice_length + 1).map(FixedLenSlice))
2058+
}
20132059
// Any other constructor can be used unchanged.
20142060
_ => split_ctors.push(ctor),
20152061
}
@@ -2252,7 +2298,7 @@ fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
22522298

22532299
PatKind::Array { ref prefix, ref slice, ref suffix }
22542300
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
2255-
FixedLenSlice(..) => {
2301+
FixedLenSlice(..) | VarLenSlice(..) => {
22562302
let pat_len = prefix.len() + suffix.len();
22572303
if let Some(slice_count) = ctor_wild_subpatterns.len().checked_sub(pat_len) {
22582304
if slice_count == 0 || slice.is_some() {

0 commit comments

Comments
 (0)