&self,
cx: &mut MatchCheckCtxt<'a, 'tcx>,
constructor: &Constructor<'tcx>,
- wild_patterns: &[&'q Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'q Pat<'tcx>],
) -> Option<PatStack<'q, 'tcx>>
where
'a: 'q,
'p: 'q,
{
- specialize(cx, self, constructor, wild_patterns)
+ let new_heads = specialize_one_pattern(cx, self.head(), constructor, ctor_wild_subpatterns);
+ new_heads.map(|mut new_head| {
+ new_head.0.extend_from_slice(&self.0[1..]);
+ new_head
+ })
}
}
&self,
cx: &mut MatchCheckCtxt<'a, 'tcx>,
constructor: &Constructor<'tcx>,
- wild_patterns: &[&'q Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'q Pat<'tcx>],
) -> Matrix<'q, 'tcx>
where
'a: 'q,
Matrix(
self.0
.iter()
- .filter_map(|r| r.specialize_constructor(cx, constructor, wild_patterns))
+ .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns))
.collect(),
)
}
}
}
+ /// This returns one wildcard pattern for each argument to this constructor.
fn wildcard_subpatterns<'a>(
&self,
cx: &MatchCheckCtxt<'a, 'tcx>,
ty: Ty<'tcx>,
- ) -> Vec<Pat<'tcx>> {
- constructor_sub_pattern_tys(cx, self, ty)
- .into_iter()
- .map(|ty| Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild })
- .collect()
+ ) -> impl Iterator<Item = Pat<'tcx>> + DoubleEndedIterator {
+ constructor_sub_pattern_tys(cx, self, ty).into_iter().map(|ty| Pat {
+ ty,
+ span: DUMMY_SP,
+ kind: box PatKind::Wild,
+ })
}
/// This computes the arity of a constructor. The arity of a constructor
_ => 0,
}
}
+
+ /// Apply a constructor to a list of patterns, yielding a new pattern. `pats`
+ /// must have as many elements as this constructor's arity.
+ ///
+ /// Examples:
+ /// self: Single
+ /// ty: tuple of 3 elements
+ /// pats: [10, 20, _] => (10, 20, _)
+ ///
+ /// self: Option::Some
+ /// ty: Option<bool>
+ /// pats: [false] => Some(false)
+ fn apply<'a>(
+ &self,
+ cx: &MatchCheckCtxt<'a, 'tcx>,
+ ty: Ty<'tcx>,
+ pats: impl IntoIterator<Item = Pat<'tcx>>,
+ ) -> Pat<'tcx> {
+ let mut pats = pats.into_iter();
+ let pat = match ty.kind {
+ ty::Adt(..) | ty::Tuple(..) => {
+ let pats = pats
+ .enumerate()
+ .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
+ .collect();
+
+ if let ty::Adt(adt, substs) = ty.kind {
+ if adt.is_enum() {
+ PatKind::Variant {
+ adt_def: adt,
+ substs,
+ variant_index: self.variant_index_for_adt(cx, adt),
+ subpatterns: pats,
+ }
+ } else {
+ PatKind::Leaf { subpatterns: pats }
+ }
+ } else {
+ PatKind::Leaf { subpatterns: pats }
+ }
+ }
+
+ ty::Ref(..) => PatKind::Deref { subpattern: pats.nth(0).unwrap() },
+
+ ty::Slice(_) | ty::Array(..) => {
+ PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
+ }
+
+ _ => match *self {
+ ConstantValue(value, _) => PatKind::Constant { value },
+ ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange {
+ lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
+ hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
+ end,
+ }),
+ _ => PatKind::Wild,
+ },
+ };
+
+ Pat { ty, span: DUMMY_SP, kind: Box::new(pat) }
+ }
+
+ /// Like `apply`, but where all the subpatterns are wildcards `_`.
+ fn apply_wildcards<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
+ let pats = self.wildcard_subpatterns(cx, ty).rev();
+ self.apply(cx, ty, pats)
+ }
}
#[derive(Clone, Debug)]
self.0.into_iter().next().unwrap()
}
- fn push_wild_constructor<'a>(
- mut self,
- cx: &MatchCheckCtxt<'a, 'tcx>,
- ctor: &Constructor<'tcx>,
- ty: Ty<'tcx>,
- ) -> Self {
- self.0.extend(ctor.wildcard_subpatterns(cx, ty));
- self.apply_constructor(cx, ctor, ty)
- }
-
/// Constructs a partial witness for a pattern given a list of
/// patterns expanded by the specialization step.
///
let arity = ctor.arity(cx, ty);
let pat = {
let len = self.0.len() as u64;
- let mut pats = self.0.drain((len - arity) as usize..).rev();
-
- match ty.kind {
- ty::Adt(..) | ty::Tuple(..) => {
- let pats = pats
- .enumerate()
- .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p })
- .collect();
-
- if let ty::Adt(adt, substs) = ty.kind {
- if adt.is_enum() {
- PatKind::Variant {
- adt_def: adt,
- substs,
- variant_index: ctor.variant_index_for_adt(cx, adt),
- subpatterns: pats,
- }
- } else {
- PatKind::Leaf { subpatterns: pats }
- }
- } else {
- PatKind::Leaf { subpatterns: pats }
- }
- }
-
- ty::Ref(..) => PatKind::Deref { subpattern: pats.nth(0).unwrap() },
-
- ty::Slice(_) | ty::Array(..) => {
- PatKind::Slice { prefix: pats.collect(), slice: None, suffix: vec![] }
- }
-
- _ => match *ctor {
- ConstantValue(value, _) => PatKind::Constant { value },
- ConstantRange(lo, hi, ty, end, _) => PatKind::Range(PatRange {
- lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
- hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
- end,
- }),
- _ => PatKind::Wild,
- },
- }
+ let pats = self.0.drain((len - arity) as usize..).rev();
+ ctor.apply(cx, ty, pats)
};
- self.0.push(Pat { ty, span: DUMMY_SP, kind: Box::new(pat) });
+ self.0.push(pat);
self
}
}
}
-// A request for missing constructor data in terms of either:
-// - whether or not there any missing constructors; or
-// - the actual set of missing constructors.
-#[derive(PartialEq)]
-enum MissingCtorsInfo {
- Emptiness,
- Ctors,
+// A struct to compute a set of constructors equivalent to `all_ctors \ used_ctors`.
+struct MissingConstructors<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ all_ctors: Vec<Constructor<'tcx>>,
+ used_ctors: Vec<Constructor<'tcx>>,
}
-// Used by `compute_missing_ctors`.
-#[derive(Debug, PartialEq)]
-enum MissingCtors<'tcx> {
- Empty,
- NonEmpty,
+impl<'tcx> MissingConstructors<'tcx> {
+ fn new(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ all_ctors: Vec<Constructor<'tcx>>,
+ used_ctors: Vec<Constructor<'tcx>>,
+ ) -> Self {
+ MissingConstructors { tcx, param_env, all_ctors, used_ctors }
+ }
- // Note that the Vec can be empty.
- Ctors(Vec<Constructor<'tcx>>),
-}
+ fn into_inner(self) -> (Vec<Constructor<'tcx>>, Vec<Constructor<'tcx>>) {
+ (self.all_ctors, self.used_ctors)
+ }
-// When `info` is `MissingCtorsInfo::Ctors`, compute a set of constructors
-// equivalent to `all_ctors \ used_ctors`. When `info` is
-// `MissingCtorsInfo::Emptiness`, just determines if that set is empty or not.
-// (The split logic gives a performance win, because we always need to know if
-// the set is empty, but we rarely need the full set, and it can be expensive
-// to compute the full set.)
-fn compute_missing_ctors<'tcx>(
- info: MissingCtorsInfo,
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- all_ctors: &Vec<Constructor<'tcx>>,
- used_ctors: &Vec<Constructor<'tcx>>,
-) -> MissingCtors<'tcx> {
- let mut missing_ctors = vec![];
-
- for req_ctor in all_ctors {
- let mut refined_ctors = vec![req_ctor.clone()];
- for used_ctor in used_ctors {
- if used_ctor == req_ctor {
- // If a constructor appears in a `match` arm, we can
- // eliminate it straight away.
- refined_ctors = vec![]
- } else if let Some(interval) = IntRange::from_ctor(tcx, param_env, used_ctor) {
- // 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);
- }
+ fn is_empty(&self) -> bool {
+ self.iter().next().is_none()
+ }
+ /// Whether this contains all the constructors for the given type or only a
+ /// subset.
+ fn all_ctors_are_missing(&self) -> bool {
+ self.used_ctors.is_empty()
+ }
- // If the constructor patterns that have been considered so far
- // already cover the entire range of values, then we the
- // constructor is not missing, and we can move on to the next one.
- if refined_ctors.is_empty() {
- break;
- }
- }
- // If a constructor has not been matched, then it is missing.
- // We add `refined_ctors` instead of `req_ctor`, because then we can
- // provide more detailed error information about precisely which
- // ranges have been omitted.
- if info == MissingCtorsInfo::Emptiness {
- if !refined_ctors.is_empty() {
- // The set is non-empty; return early.
- return MissingCtors::NonEmpty;
+ /// Iterate over all_ctors \ used_ctors
+ fn iter<'a>(&'a self) -> impl Iterator<Item = Constructor<'tcx>> + Captures<'a> {
+ self.all_ctors.iter().flat_map(move |req_ctor| {
+ let mut refined_ctors = vec![req_ctor.clone()];
+ for used_ctor in &self.used_ctors {
+ if used_ctor == req_ctor {
+ // If a constructor appears in a `match` arm, we can
+ // eliminate it straight away.
+ refined_ctors = vec![]
+ } else if let Some(interval) =
+ IntRange::from_ctor(self.tcx, self.param_env, used_ctor)
+ {
+ // Refine the required constructors for the type by subtracting
+ // the range defined by the current constructor pattern.
+ refined_ctors = interval.subtract_from(self.tcx, self.param_env, refined_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 refined_ctors.is_empty() {
+ break;
+ }
}
- } else {
- missing_ctors.extend(refined_ctors);
- }
+
+ // If a constructor has not been matched, then it is missing.
+ // We add `refined_ctors` instead of `req_ctor`, because then we can
+ // provide more detailed error information about precisely which
+ // ranges have been omitted.
+ refined_ctors
+ })
}
+}
- if info == MissingCtorsInfo::Emptiness {
- // If we reached here, the set is empty.
- MissingCtors::Empty
- } else {
- MissingCtors::Ctors(missing_ctors)
+impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let ctors: Vec<_> = self.iter().collect();
+ write!(f, "{:?}", ctors)
}
}
cx: &mut MatchCheckCtxt<'a, 'tcx>,
matrix: &Matrix<'p, 'tcx>,
v: &PatStack<'_, 'tcx>,
- witness: WitnessPreference,
+ witness_preference: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
let &Matrix(ref rows) = matrix;
// the type of the tuple we're checking is inhabited or not.
if v.is_empty() {
return if rows.is_empty() {
- match witness {
+ match witness_preference {
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
LeaveOutWitness => Useful,
}
Some(hir_id),
)
.into_iter()
- .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id))
+ .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
let all_ctors = all_constructors(cx, pcx);
debug!("all_ctors = {:#?}", all_ctors);
+ let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+ let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
+
// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
// from the first column.
// needed for that case.
// Missing constructors are those that are not matched by any
- // non-wildcard patterns in the current column. We always determine if
- // the set is empty, but we only fully construct them on-demand,
- // because they're rarely used and can be big.
- let cheap_missing_ctors = compute_missing_ctors(
- MissingCtorsInfo::Emptiness,
- cx.tcx,
- cx.param_env,
- &all_ctors,
- &used_ctors,
- );
+ // non-wildcard patterns in the current column. To determine if
+ // the set is empty, we can check that `.peek().is_none()`, so
+ // we only fully construct them on-demand, because they're rarely used and can be big.
+ let missing_ctors = MissingConstructors::new(cx.tcx, cx.param_env, all_ctors, used_ctors);
- let is_privately_empty = all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
- let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
debug!(
- "cheap_missing_ctors={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
- cheap_missing_ctors, is_privately_empty, is_declared_nonexhaustive
+ "missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
+ missing_ctors.is_empty(),
+ is_privately_empty,
+ is_declared_nonexhaustive
);
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
|| is_declared_nonexhaustive
|| (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
- if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
+ if missing_ctors.is_empty() && !is_non_exhaustive {
+ let (all_ctors, _) = missing_ctors.into_inner();
split_grouped_constructors(
cx.tcx,
cx.param_env,
None,
)
.into_iter()
- .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness, hir_id))
+ .map(|c| is_useful_specialized(cx, matrix, v, c, pcx.ty, witness_preference, hir_id))
.find(|result| result.is_useful())
.unwrap_or(NotUseful)
} else {
let matrix = matrix.specialize_wildcard();
let v = v.to_tail();
- match is_useful(cx, &matrix, &v, witness, hir_id) {
- UsefulWithWitness(pats) => {
+ match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
+ UsefulWithWitness(witnesses) => {
let cx = &*cx;
// In this case, there's at least one "free"
// constructor that is only matched against by
// 1) If the user is matching against a non-exhaustive
// enum, there is no point in enumerating all possible
// variants, because the user can't actually match
- // against them himself, e.g., in an example like:
+ // against them themselves, e.g., in an example like:
// ```
// let err: io::ErrorKind = ...;
// match err {
// `(<direction-1>, <direction-2>, true)` - we are
// satisfied with `(_, _, true)`. In this case,
// `used_ctors` is empty.
- let new_witnesses = if is_non_exhaustive || used_ctors.is_empty() {
- // All constructors are unused. Add wild patterns
+ let new_patterns = if is_non_exhaustive || missing_ctors.all_ctors_are_missing()
+ {
+ // All constructors are unused. Add a wild pattern
// rather than each individual constructor.
- pats.into_iter()
- .map(|mut witness| {
- witness.0.push(Pat {
- ty: pcx.ty,
- span: DUMMY_SP,
- kind: box PatKind::Wild,
- });
- witness
- })
- .collect()
+ vec![Pat { ty: pcx.ty, span: DUMMY_SP, kind: box PatKind::Wild }]
} else {
- let expensive_missing_ctors = compute_missing_ctors(
- MissingCtorsInfo::Ctors,
- cx.tcx,
- cx.param_env,
- &all_ctors,
- &used_ctors,
- );
- if let MissingCtors::Ctors(missing_ctors) = expensive_missing_ctors {
- pats.into_iter()
- .flat_map(|witness| {
- missing_ctors.iter().map(move |ctor| {
- // Extends the witness with a "wild" version of this
- // constructor, that matches everything that can be built with
- // it. For example, if `ctor` is a `Constructor::Variant` for
- // `Option::Some`, this pushes the witness for `Some(_)`.
- witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
- })
- })
- .collect()
- } else {
- bug!("cheap missing ctors")
- }
+ // Construct for each missing constructor a "wild" version of this
+ // constructor, that matches everything that can be built with
+ // it. For example, if `ctor` is a `Constructor::Variant` for
+ // `Option::Some`, we get the pattern `Some(_)`.
+ missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, pcx.ty)).collect()
};
+ // Add the new patterns to each witness
+ let new_witnesses = witnesses
+ .into_iter()
+ .flat_map(|witness| {
+ new_patterns.iter().map(move |pat| {
+ let mut witness = witness.clone();
+ witness.0.push(pat.clone());
+ witness
+ })
+ })
+ .collect();
UsefulWithWitness(new_witnesses)
}
result => result,
v: &PatStack<'_, 'tcx>,
ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
- witness: WitnessPreference,
+ witness_preference: WitnessPreference,
hir_id: HirId,
) -> Usefulness<'tcx> {
debug!("is_useful_specialized({:#?}, {:#?}, {:?})", v, ctor, lty);
- let wild_patterns_owned = ctor.wildcard_subpatterns(cx, lty);
- let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect();
- let matrix = matrix.specialize_constructor(cx, &ctor, &wild_patterns);
- match v.specialize_constructor(cx, &ctor, &wild_patterns) {
- Some(v) => match is_useful(cx, &matrix, &v, witness, hir_id) {
+ let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty).collect();
+ let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
+ let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
+ match v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns) {
+ Some(v) => match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
UsefulWithWitness(witnesses) => UsefulWithWitness(
witnesses
.into_iter()
lint_overlapping_patterns(tcx, hir_id, ctor_range, ty, overlaps);
- // We're going to iterate through every pair of borders, making sure that each
- // represents an interval of nonnegative length, and convert each such interval
- // into a constructor.
+ // 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
+ // interval into a constructor.
for IntRange { range, .. } in
borders.windows(2).filter_map(|window| match (window[0], window[1]) {
(Border::JustBefore(n), Border::JustBefore(m)) => {
fn patterns_for_variant<'p, 'a: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
subpatterns: &'p [FieldPat<'tcx>],
- wild_patterns: &[&'p Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'p Pat<'tcx>],
is_non_exhaustive: bool,
) -> PatStack<'p, 'tcx> {
- let mut result = SmallVec::from_slice(wild_patterns);
+ let mut result = SmallVec::from_slice(ctor_wild_subpatterns);
for subpat in subpatterns {
if !is_non_exhaustive || !cx.is_uninhabited(subpat.pattern.ty) {
}
}
- debug!("patterns_for_variant({:#?}, {:#?}) = {:#?}", subpatterns, wild_patterns, result);
+ debug!(
+ "patterns_for_variant({:#?}, {:#?}) = {:#?}",
+ subpatterns, ctor_wild_subpatterns, result
+ );
PatStack::from_vec(result)
}
-/// This is the main specialization step. It expands the first pattern in the given row
+/// This is the main specialization step. It expands the pattern
/// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
/// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
+/// Returns `None` if the pattern does not have the given constructor.
///
/// OTOH, slice patterns with a subslice pattern (tail @ ..) can be expanded into multiple
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
-fn specialize<'p, 'a: 'p, 'q: 'p, 'tcx>(
+fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
- r: &PatStack<'q, 'tcx>,
+ pat: &'q Pat<'tcx>,
constructor: &Constructor<'tcx>,
- wild_patterns: &[&'p Pat<'tcx>],
+ ctor_wild_subpatterns: &[&'p Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
- let pat = r.head();
+ let result = match *pat.kind {
+ PatKind::AscribeUserType { ref subpattern, .. } => PatStack::from_pattern(subpattern)
+ .specialize_constructor(cx, constructor, ctor_wild_subpatterns),
- let new_head = match *pat.kind {
- PatKind::AscribeUserType { ref subpattern, .. } => {
- specialize(cx, &PatStack::from_pattern(subpattern), constructor, wild_patterns)
+ PatKind::Binding { .. } | PatKind::Wild => {
+ Some(PatStack::from_slice(ctor_wild_subpatterns))
}
- PatKind::Binding { .. } | PatKind::Wild => Some(PatStack::from_slice(wild_patterns)),
-
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let ref variant = adt_def.variants[variant_index];
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !cx.is_local(pat.ty);
Some(Variant(variant.def_id))
.filter(|variant_constructor| variant_constructor == constructor)
- .map(|_| patterns_for_variant(cx, subpatterns, wild_patterns, is_non_exhaustive))
+ .map(|_| {
+ patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, is_non_exhaustive)
+ })
}
PatKind::Leaf { ref subpatterns } => {
- Some(patterns_for_variant(cx, subpatterns, wild_patterns, false))
+ Some(patterns_for_variant(cx, subpatterns, ctor_wild_subpatterns, false))
}
PatKind::Deref { ref subpattern } => Some(PatStack::from_pattern(subpattern)),
constructor,
),
};
- if wild_patterns.len() as u64 == n {
+ if ctor_wild_subpatterns.len() as u64 == n {
// convert a constant slice/array pattern to a list of patterns.
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
let ptr = Pointer::new(AllocId(0), offset);
| PatKind::Slice { ref prefix, ref slice, ref suffix } => match *constructor {
Slice(..) => {
let pat_len = prefix.len() + suffix.len();
- if let Some(slice_count) = wild_patterns.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() {
Some(
prefix
.iter()
.chain(
- wild_patterns
+ ctor_wild_subpatterns
.iter()
.map(|p| *p)
.skip(prefix.len())
bug!("support for or-patterns has not been fully implemented yet.");
}
};
- debug!("specialize({:#?}, {:#?}) = {:#?}", r.head(), wild_patterns, new_head);
+ debug!("specialize({:#?}, {:#?}) = {:#?}", pat, ctor_wild_subpatterns, result);
- new_head.map(|head| {
- let mut head = head.0;
- head.extend_from_slice(&r.0[1..]);
- PatStack::from_vec(head)
- })
+ result
}