Split Single
ctor into more specific variants
This commit is contained in:
parent
4d1bd0db7f
commit
b111b2e839
4 changed files with 80 additions and 52 deletions
|
@ -874,7 +874,7 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
|
||||||
use Constructor::*;
|
use Constructor::*;
|
||||||
match pat.ctor() {
|
match pat.ctor() {
|
||||||
Wildcard => true,
|
Wildcard => true,
|
||||||
Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
|
Struct | Ref => pat.iter_fields().all(|pat| pat_is_catchall(pat)),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -631,11 +631,16 @@ impl OpaqueId {
|
||||||
/// `Fields`.
|
/// `Fields`.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Constructor<'tcx> {
|
pub enum Constructor<'tcx> {
|
||||||
/// The constructor for patterns that have a single constructor, like tuples, struct patterns,
|
/// Tuples and structs.
|
||||||
/// and references. Fixed-length arrays are treated separately with `Slice`.
|
Struct,
|
||||||
Single,
|
|
||||||
/// Enum variants.
|
/// Enum variants.
|
||||||
Variant(VariantIdx),
|
Variant(VariantIdx),
|
||||||
|
/// References
|
||||||
|
Ref,
|
||||||
|
/// Array and slice patterns.
|
||||||
|
Slice(Slice),
|
||||||
|
/// Union field accesses.
|
||||||
|
UnionField,
|
||||||
/// Booleans
|
/// Booleans
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||||
|
@ -645,8 +650,6 @@ pub enum Constructor<'tcx> {
|
||||||
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
|
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
|
||||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||||
Str(Const<'tcx>),
|
Str(Const<'tcx>),
|
||||||
/// Array and slice patterns.
|
|
||||||
Slice(Slice),
|
|
||||||
/// Constants that must not be matched structurally. They are treated as black boxes for the
|
/// Constants that must not be matched structurally. They are treated as black boxes for the
|
||||||
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
|
/// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a
|
||||||
/// match exhaustive.
|
/// match exhaustive.
|
||||||
|
@ -723,7 +726,9 @@ impl<'tcx> Constructor<'tcx> {
|
||||||
// Only a wildcard pattern can match these special constructors.
|
// Only a wildcard pattern can match these special constructors.
|
||||||
(Missing { .. } | NonExhaustive | Hidden, _) => false,
|
(Missing { .. } | NonExhaustive | Hidden, _) => false,
|
||||||
|
|
||||||
(Single, Single) => true,
|
(Struct, Struct) => true,
|
||||||
|
(Ref, Ref) => true,
|
||||||
|
(UnionField, UnionField) => true,
|
||||||
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
||||||
(Bool(self_b), Bool(other_b)) => self_b == other_b,
|
(Bool(self_b), Bool(other_b)) => self_b == other_b,
|
||||||
|
|
||||||
|
@ -786,12 +791,15 @@ pub enum VariantVisibility {
|
||||||
/// `exhaustive_patterns` feature.
|
/// `exhaustive_patterns` feature.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConstructorSet {
|
pub enum ConstructorSet {
|
||||||
/// The type has a single constructor, e.g. `&T` or a struct. `empty` tracks whether the
|
/// The type is a tuple or struct. `empty` tracks whether the type is empty.
|
||||||
/// constructor is empty.
|
Struct { empty: bool },
|
||||||
Single { empty: bool },
|
|
||||||
/// This type has the following list of constructors. If `variants` is empty and
|
/// This type has the following list of constructors. If `variants` is empty and
|
||||||
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
|
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
|
||||||
Variants { variants: IndexVec<VariantIdx, VariantVisibility>, non_exhaustive: bool },
|
Variants { variants: IndexVec<VariantIdx, VariantVisibility>, non_exhaustive: bool },
|
||||||
|
/// The type is `&T`.
|
||||||
|
Ref,
|
||||||
|
/// The type is a union.
|
||||||
|
Union,
|
||||||
/// Booleans.
|
/// Booleans.
|
||||||
Bool,
|
Bool,
|
||||||
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
|
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
|
||||||
|
@ -866,13 +874,27 @@ impl ConstructorSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
ConstructorSet::Single { empty } => {
|
ConstructorSet::Struct { empty } => {
|
||||||
if !seen.is_empty() {
|
if !seen.is_empty() {
|
||||||
present.push(Single);
|
present.push(Struct);
|
||||||
} else if *empty {
|
} else if *empty {
|
||||||
missing_empty.push(Single);
|
missing_empty.push(Struct);
|
||||||
} else {
|
} else {
|
||||||
missing.push(Single);
|
missing.push(Struct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstructorSet::Ref => {
|
||||||
|
if !seen.is_empty() {
|
||||||
|
present.push(Ref);
|
||||||
|
} else {
|
||||||
|
missing.push(Ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstructorSet::Union => {
|
||||||
|
if !seen.is_empty() {
|
||||||
|
present.push(UnionField);
|
||||||
|
} else {
|
||||||
|
missing.push(UnionField);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstructorSet::Variants { variants, non_exhaustive } => {
|
ConstructorSet::Variants { variants, non_exhaustive } => {
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
) -> VariantIdx {
|
) -> VariantIdx {
|
||||||
match *ctor {
|
match *ctor {
|
||||||
Variant(idx) => idx,
|
Variant(idx) => idx,
|
||||||
Single => {
|
Struct | UnionField => {
|
||||||
assert!(!adt.is_enum());
|
assert!(!adt.is_enum());
|
||||||
FIRST_VARIANT
|
FIRST_VARIANT
|
||||||
}
|
}
|
||||||
|
@ -123,9 +123,8 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
) -> &'p [DeconstructedPat<'p, 'tcx>] {
|
) -> &'p [DeconstructedPat<'p, 'tcx>] {
|
||||||
let cx = self;
|
let cx = self;
|
||||||
match ctor {
|
match ctor {
|
||||||
Single | Variant(_) => match ty.kind() {
|
Struct | Variant(_) | UnionField => match ty.kind() {
|
||||||
ty::Tuple(fs) => cx.alloc_wildcard_slice(fs.iter()),
|
ty::Tuple(fs) => cx.alloc_wildcard_slice(fs.iter()),
|
||||||
ty::Ref(_, rty, _) => cx.alloc_wildcard_slice(once(*rty)),
|
|
||||||
ty::Adt(adt, args) => {
|
ty::Adt(adt, args) => {
|
||||||
if adt.is_box() {
|
if adt.is_box() {
|
||||||
// The only legal patterns of type `Box` (outside `std`) are `_` and box
|
// The only legal patterns of type `Box` (outside `std`) are `_` and box
|
||||||
|
@ -138,7 +137,11 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
cx.alloc_wildcard_slice(tys)
|
cx.alloc_wildcard_slice(tys)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
|
_ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
|
||||||
|
},
|
||||||
|
Ref => match ty.kind() {
|
||||||
|
ty::Ref(_, rty, _) => cx.alloc_wildcard_slice(once(*rty)),
|
||||||
|
_ => bug!("Unexpected type for `Ref` constructor: {ty:?}"),
|
||||||
},
|
},
|
||||||
Slice(slice) => match *ty.kind() {
|
Slice(slice) => match *ty.kind() {
|
||||||
ty::Slice(ty) | ty::Array(ty, _) => {
|
ty::Slice(ty) | ty::Array(ty, _) => {
|
||||||
|
@ -167,9 +170,8 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
/// `Fields::wildcards`.
|
/// `Fields::wildcards`.
|
||||||
pub(crate) fn ctor_arity(&self, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> usize {
|
pub(crate) fn ctor_arity(&self, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> usize {
|
||||||
match ctor {
|
match ctor {
|
||||||
Single | Variant(_) => match ty.kind() {
|
Struct | Variant(_) | UnionField => match ty.kind() {
|
||||||
ty::Tuple(fs) => fs.len(),
|
ty::Tuple(fs) => fs.len(),
|
||||||
ty::Ref(..) => 1,
|
|
||||||
ty::Adt(adt, ..) => {
|
ty::Adt(adt, ..) => {
|
||||||
if adt.is_box() {
|
if adt.is_box() {
|
||||||
// The only legal patterns of type `Box` (outside `std`) are `_` and box
|
// The only legal patterns of type `Box` (outside `std`) are `_` and box
|
||||||
|
@ -181,8 +183,9 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
self.list_variant_nonhidden_fields(ty, variant).count()
|
self.list_variant_nonhidden_fields(ty, variant).count()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
|
_ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
|
||||||
},
|
},
|
||||||
|
Ref => 1,
|
||||||
Slice(slice) => slice.arity(),
|
Slice(slice) => slice.arity(),
|
||||||
Bool(..)
|
Bool(..)
|
||||||
| IntRange(..)
|
| IntRange(..)
|
||||||
|
@ -298,9 +301,9 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
|
ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => {
|
ty::Adt(def, _) if def.is_union() => ConstructorSet::Union,
|
||||||
ConstructorSet::Single { empty: cx.is_uninhabited(ty) }
|
ty::Adt(..) | ty::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(ty) },
|
||||||
}
|
ty::Ref(..) => ConstructorSet::Ref,
|
||||||
ty::Never => ConstructorSet::NoConstructors,
|
ty::Never => ConstructorSet::NoConstructors,
|
||||||
// This type is one for which we cannot list constructors, like `str` or `f64`.
|
// This type is one for which we cannot list constructors, like `str` or `f64`.
|
||||||
// FIXME(Nadrieril): which of these are actually allowed?
|
// FIXME(Nadrieril): which of these are actually allowed?
|
||||||
|
@ -359,13 +362,18 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
fields = &[];
|
fields = &[];
|
||||||
}
|
}
|
||||||
PatKind::Deref { subpattern } => {
|
PatKind::Deref { subpattern } => {
|
||||||
ctor = Single;
|
|
||||||
fields = singleton(self.lower_pat(subpattern));
|
fields = singleton(self.lower_pat(subpattern));
|
||||||
|
ctor = match pat.ty.kind() {
|
||||||
|
// This is a box pattern.
|
||||||
|
ty::Adt(adt, ..) if adt.is_box() => Struct,
|
||||||
|
ty::Ref(..) => Ref,
|
||||||
|
_ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => {
|
||||||
match pat.ty.kind() {
|
match pat.ty.kind() {
|
||||||
ty::Tuple(fs) => {
|
ty::Tuple(fs) => {
|
||||||
ctor = Single;
|
ctor = Struct;
|
||||||
let mut wilds: SmallVec<[_; 2]> =
|
let mut wilds: SmallVec<[_; 2]> =
|
||||||
fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect();
|
fs.iter().map(|ty| DeconstructedPat::wildcard(ty, pat.span)).collect();
|
||||||
for pat in subpatterns {
|
for pat in subpatterns {
|
||||||
|
@ -380,7 +388,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
// _)` or a box pattern. As a hack to avoid an ICE with the former, we
|
// _)` or a box pattern. As a hack to avoid an ICE with the former, we
|
||||||
// ignore other fields than the first one. This will trigger an error later
|
// ignore other fields than the first one. This will trigger an error later
|
||||||
// anyway.
|
// anyway.
|
||||||
// See https://github.com/rust-lang/rust/issues/82772 ,
|
// See https://github.com/rust-lang/rust/issues/82772,
|
||||||
// explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
|
// explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977
|
||||||
// The problem is that we can't know from the type whether we'll match
|
// The problem is that we can't know from the type whether we'll match
|
||||||
// normally or through box-patterns. We'll have to figure out a proper
|
// normally or through box-patterns. We'll have to figure out a proper
|
||||||
|
@ -392,12 +400,13 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
DeconstructedPat::wildcard(args.type_at(0), pat.span)
|
DeconstructedPat::wildcard(args.type_at(0), pat.span)
|
||||||
};
|
};
|
||||||
ctor = Single;
|
ctor = Struct;
|
||||||
fields = singleton(pat);
|
fields = singleton(pat);
|
||||||
}
|
}
|
||||||
ty::Adt(adt, _) => {
|
ty::Adt(adt, _) => {
|
||||||
ctor = match pat.kind {
|
ctor = match pat.kind {
|
||||||
PatKind::Leaf { .. } => Single,
|
PatKind::Leaf { .. } if adt.is_union() => UnionField,
|
||||||
|
PatKind::Leaf { .. } => Struct,
|
||||||
PatKind::Variant { variant_index, .. } => Variant(variant_index),
|
PatKind::Variant { variant_index, .. } => Variant(variant_index),
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
|
@ -477,11 +486,11 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
// with other `Deref` patterns. This could have been done in `const_to_pat`,
|
// with other `Deref` patterns. This could have been done in `const_to_pat`,
|
||||||
// but that causes issues with the rest of the matching code.
|
// but that causes issues with the rest of the matching code.
|
||||||
// So here, the constructor for a `"foo"` pattern is `&` (represented by
|
// So here, the constructor for a `"foo"` pattern is `&` (represented by
|
||||||
// `Single`), and has one field. That field has constructor `Str(value)` and no
|
// `Ref`), and has one field. That field has constructor `Str(value)` and no
|
||||||
// fields.
|
// subfields.
|
||||||
// Note: `t` is `str`, not `&str`.
|
// Note: `t` is `str`, not `&str`.
|
||||||
let subpattern = DeconstructedPat::new(Str(*value), &[], *t, pat.span);
|
let subpattern = DeconstructedPat::new(Str(*value), &[], *t, pat.span);
|
||||||
ctor = Single;
|
ctor = Ref;
|
||||||
fields = singleton(subpattern)
|
fields = singleton(subpattern)
|
||||||
}
|
}
|
||||||
// All constants that can be structurally matched have already been expanded
|
// All constants that can be structurally matched have already been expanded
|
||||||
|
@ -657,7 +666,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
let kind = match pat.ctor() {
|
let kind = match pat.ctor() {
|
||||||
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
|
Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
|
||||||
IntRange(range) => return self.hoist_pat_range(range, pat.ty()),
|
IntRange(range) => return self.hoist_pat_range(range, pat.ty()),
|
||||||
Single | Variant(_) => match pat.ty().kind() {
|
Struct | Variant(_) | UnionField => match pat.ty().kind() {
|
||||||
ty::Tuple(..) => PatKind::Leaf {
|
ty::Tuple(..) => PatKind::Leaf {
|
||||||
subpatterns: subpatterns
|
subpatterns: subpatterns
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -686,13 +695,13 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
PatKind::Leaf { subpatterns }
|
PatKind::Leaf { subpatterns }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
|
||||||
// be careful to reconstruct the correct constant pattern here. However a string
|
|
||||||
// literal pattern will never be reported as a non-exhaustiveness witness, so we
|
|
||||||
// ignore this issue.
|
|
||||||
ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
|
|
||||||
_ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), pat.ty()),
|
_ => bug!("unexpected ctor for type {:?} {:?}", pat.ctor(), pat.ty()),
|
||||||
},
|
},
|
||||||
|
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
||||||
|
// be careful to reconstruct the correct constant pattern here. However a string
|
||||||
|
// literal pattern will never be reported as a non-exhaustiveness witness, so we
|
||||||
|
// ignore this issue.
|
||||||
|
Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() },
|
||||||
Slice(slice) => {
|
Slice(slice) => {
|
||||||
match slice.kind {
|
match slice.kind {
|
||||||
SliceKind::FixedLen(_) => PatKind::Slice {
|
SliceKind::FixedLen(_) => PatKind::Slice {
|
||||||
|
@ -758,7 +767,7 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
let mut start_or_comma = || start_or_continue(", ");
|
let mut start_or_comma = || start_or_continue(", ");
|
||||||
|
|
||||||
match pat.ctor() {
|
match pat.ctor() {
|
||||||
Single | Variant(_) => match pat.ty().kind() {
|
Struct | Variant(_) | UnionField => match pat.ty().kind() {
|
||||||
ty::Adt(def, _) if def.is_box() => {
|
ty::Adt(def, _) if def.is_box() => {
|
||||||
// Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
|
// Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
|
||||||
// of `std`). So this branch is only reachable when the feature is enabled and
|
// of `std`). So this branch is only reachable when the feature is enabled and
|
||||||
|
@ -789,15 +798,15 @@ impl<'p, 'tcx> MatchCheckCtxt<'p, 'tcx> {
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
|
||||||
// be careful to detect strings here. However a string literal pattern will never
|
|
||||||
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
|
||||||
ty::Ref(_, _, mutbl) => {
|
|
||||||
let subpattern = pat.iter_fields().next().unwrap();
|
|
||||||
write!(f, "&{}{:?}", mutbl.prefix_str(), subpattern)
|
|
||||||
}
|
|
||||||
_ => write!(f, "_"),
|
_ => write!(f, "_"),
|
||||||
},
|
},
|
||||||
|
// Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
|
||||||
|
// be careful to detect strings here. However a string literal pattern will never
|
||||||
|
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
||||||
|
Ref => {
|
||||||
|
let subpattern = pat.iter_fields().next().unwrap();
|
||||||
|
write!(f, "&{:?}", subpattern)
|
||||||
|
}
|
||||||
Slice(slice) => {
|
Slice(slice) => {
|
||||||
let mut subpatterns = pat.iter_fields();
|
let mut subpatterns = pat.iter_fields();
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
|
|
|
@ -629,12 +629,9 @@ impl ValidityConstraint {
|
||||||
///
|
///
|
||||||
/// Pending further opsem decisions, the current behavior is: validity is preserved, except
|
/// Pending further opsem decisions, the current behavior is: validity is preserved, except
|
||||||
/// inside `&` and union fields where validity is reset to `MaybeInvalid`.
|
/// inside `&` and union fields where validity is reset to `MaybeInvalid`.
|
||||||
fn specialize<'tcx>(self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
|
fn specialize(self, ctor: &Constructor<'_>) -> Self {
|
||||||
// We preserve validity except when we go inside a reference or a union field.
|
// We preserve validity except when we go inside a reference or a union field.
|
||||||
if matches!(ctor, Constructor::Single)
|
if matches!(ctor, Constructor::Ref | Constructor::UnionField) {
|
||||||
&& (matches!(pcx.ty.kind(), ty::Ref(..))
|
|
||||||
|| matches!(pcx.ty.kind(), ty::Adt(def, ..) if def.is_union()))
|
|
||||||
{
|
|
||||||
// Validity of `x: &T` does not imply validity of `*x: T`.
|
// Validity of `x: &T` does not imply validity of `*x: T`.
|
||||||
MaybeInvalid
|
MaybeInvalid
|
||||||
} else {
|
} else {
|
||||||
|
@ -902,7 +899,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
|
||||||
ctor: &Constructor<'tcx>,
|
ctor: &Constructor<'tcx>,
|
||||||
) -> Matrix<'p, 'tcx> {
|
) -> Matrix<'p, 'tcx> {
|
||||||
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor);
|
let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor);
|
||||||
let new_validity = self.place_validity[0].specialize(pcx, ctor);
|
let new_validity = self.place_validity[0].specialize(ctor);
|
||||||
let new_place_validity = std::iter::repeat(new_validity)
|
let new_place_validity = std::iter::repeat(new_validity)
|
||||||
.take(ctor.arity(pcx))
|
.take(ctor.arity(pcx))
|
||||||
.chain(self.place_validity[1..].iter().copied())
|
.chain(self.place_validity[1..].iter().copied())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue