FixedLenSlice(u64),
/// Slice patterns. Captures any array constructor of `length >= i + j`.
VarLenSlice(u64, u64),
+ /// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
+ NonExhaustive,
}
// Ignore spans when comparing, they don't carry semantic information as they are only for lints.
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Constructor::Single, Constructor::Single) => true,
+ (Constructor::NonExhaustive, Constructor::NonExhaustive) => true,
(Constructor::Variant(a), Constructor::Variant(b)) => a == b,
(Constructor::ConstantValue(a, _), Constructor::ConstantValue(b, _)) => a == b,
(
// ranges have been omitted.
remaining_ctors
}
+ // This constructor is never covered by anything else
+ NonExhaustive => vec![NonExhaustive],
}
}
&self,
cx: &MatchCheckCtxt<'a, 'tcx>,
ty: Ty<'tcx>,
- ) -> impl Iterator<Item = Pat<'tcx>> + DoubleEndedIterator {
- constructor_sub_pattern_tys(cx, self, ty).into_iter().map(Pat::wildcard_from_ty)
+ ) -> Vec<Pat<'tcx>> {
+ debug!("wildcard_subpatterns({:#?}, {:?})", self, ty);
+
+ match self {
+ Single | Variant(_) => match ty.kind {
+ ty::Tuple(ref fs) => {
+ fs.into_iter().map(|t| t.expect_ty()).map(Pat::wildcard_from_ty).collect()
+ }
+ 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![],
+ },
+ FixedLenSlice(_) | VarLenSlice(..) => match ty.kind {
+ ty::Slice(ty) | ty::Array(ty, _) => {
+ let arity = self.arity(cx, ty);
+ (0..arity).map(|_| Pat::wildcard_from_ty(ty)).collect()
+ }
+ _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+ },
+ ConstantValue(..) | ConstantRange(..) | NonExhaustive => vec![],
+ }
}
/// This computes the arity of a constructor. The arity of a constructor
/// A struct pattern's arity is the number of fields it contains, etc.
fn arity<'a>(&self, cx: &MatchCheckCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> u64 {
debug!("Constructor::arity({:#?}, {:?})", self, ty);
- match ty.kind {
- ty::Tuple(ref fs) => fs.len() as u64,
- ty::Slice(..) | ty::Array(..) => match *self {
- FixedLenSlice(length) => length,
- VarLenSlice(prefix, suffix) => prefix + suffix,
- ConstantValue(..) => 0,
- _ => bug!("bad slice pattern {:?} {:?}", self, ty),
+ match self {
+ Single | Variant(_) => match ty.kind {
+ ty::Tuple(ref fs) => fs.len() as u64,
+ ty::Slice(..) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
+ ty::Ref(..) => 1,
+ ty::Adt(adt, _) => {
+ adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
+ }
+ _ => 0,
},
- ty::Ref(..) => 1,
- ty::Adt(adt, _) => {
- adt.variants[self.variant_index_for_adt(cx, adt)].fields.len() as u64
- }
- _ => 0,
+ FixedLenSlice(length) => *length,
+ VarLenSlice(prefix, suffix) => prefix + suffix,
+ ConstantValue(..) | ConstantRange(..) | NonExhaustive => 0,
}
}
pats: impl IntoIterator<Item = Pat<'tcx>>,
) -> Pat<'tcx> {
let mut subpatterns = pats.into_iter();
- let pat = match ty.kind {
- ty::Adt(..) | ty::Tuple(..) => {
- let subpatterns = subpatterns
- .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,
+
+ let pat = match self {
+ Single | Variant(_) => match ty.kind {
+ ty::Adt(..) | ty::Tuple(..) => {
+ let subpatterns = subpatterns
+ .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,
+ }
+ } else {
+ PatKind::Leaf { subpatterns }
}
} else {
PatKind::Leaf { subpatterns }
}
- } else {
- PatKind::Leaf { subpatterns }
- }
- }
-
- ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
-
- ty::Slice(_) | ty::Array(..) => match self {
- 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 {
- 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,
- }),
+ ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.nth(0).unwrap() },
+ ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", self, ty),
_ => PatKind::Wild,
},
+ FixedLenSlice(_) => {
+ PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] }
+ }
+ &VarLenSlice(prefix_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 }
+ }
+ &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,
+ }),
+ NonExhaustive => 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 subpatterns = self.wildcard_subpatterns(cx, ty).rev();
+ let subpatterns = self.wildcard_subpatterns(cx, ty).into_iter().rev();
self.apply(cx, ty, subpatterns)
}
}
}
}
};
+
+ // FIXME: currently the only way I know of something can
+ // be a privately-empty enum is when the exhaustive_patterns
+ // feature flag is not present, so this is only
+ // needed for that case.
+ let is_privately_empty = ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+ let is_declared_nonexhaustive = cx.is_non_exhaustive_enum(pcx.ty) && !cx.is_local(pcx.ty);
+ let is_non_exhaustive = is_privately_empty
+ || is_declared_nonexhaustive
+ || (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
+ if is_non_exhaustive {
+ // If our scrutinee is *privately* an empty enum, we must treat it as though it had an
+ // "unknown" constructor (in that case, all other patterns obviously can't be variants) to
+ // avoid exposing its emptyness. See the `match_privately_empty` test for details.
+ //
+ // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an additionnal
+ // "unknown" constructor. However there is no point in enumerating all possible variants,
+ // because the user can't actually match against them themselves. So we return only the
+ // fictitious constructor.
+ // E.g., in an example like:
+ // ```
+ // let err: io::ErrorKind = ...;
+ // match err {
+ // io::ErrorKind::NotFound => {},
+ // }
+ // ```
+ // we don't want to show every possible IO error, but instead have only `_` as the witness.
+ return vec![NonExhaustive];
+ }
+
ctors
}
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.
// Therefore, if there is some pattern that is unmatched by `matrix`,
// it will still be unmatched if the first constructor is replaced by
// any of the constructors in `missing_ctors`
- //
- // However, if our scrutinee is *privately* an empty enum, we
- // must treat it as though it had an "unknown" constructor (in
- // that case, all other patterns obviously can't be variants)
- // to avoid exposing its emptyness. See the `match_privately_empty`
- // test for details.
- //
- // FIXME: currently the only way I know of something can
- // be a privately-empty enum is when the exhaustive_patterns
- // feature flag is not present, so this is only
- // needed for that case.
-
- // Missing constructors are those that are not matched by any
- // 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);
- debug!(
- "missing_ctors.empty()={:#?} is_privately_empty={:#?} is_declared_nonexhaustive={:#?}",
- missing_ctors.is_empty(),
- is_privately_empty,
- is_declared_nonexhaustive
- );
+ // Missing constructors are those that are not matched by any non-wildcard patterns in the
+ // current column. 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);
- // For privately empty and non-exhaustive enums, we work as if there were an "extra"
- // `_` constructor for the type, so we can never match over all constructors.
- let is_non_exhaustive = is_privately_empty
- || is_declared_nonexhaustive
- || (pcx.ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching);
+ debug!("missing_ctors.empty()={:#?}", missing_ctors.is_empty(),);
- if missing_ctors.is_empty() && !is_non_exhaustive {
+ if missing_ctors.is_empty() {
let (all_ctors, _) = missing_ctors.into_inner();
split_grouped_constructors(cx.tcx, cx.param_env, pcx, all_ctors, matrix, DUMMY_SP, None)
.into_iter()
//
// we can report 3 witnesses: `S`, `E`, and `W`.
//
- // However, there are 2 cases where we don't want
+ // However, there is a case where we don't want
// to do this and instead report a single `_` witness:
- //
- // 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 themselves, e.g., in an example like:
- // ```
- // let err: io::ErrorKind = ...;
- // match err {
- // io::ErrorKind::NotFound => {},
- // }
- // ```
- // we don't want to show every possible IO error,
- // but instead have `_` as the witness (this is
- // actually *required* if the user specified *all*
- // IO errors, but is probably what we want in every
- // case).
- //
- // 2) If the user didn't actually specify a constructor
+ // if the user didn't actually specify a constructor
// in this arm, e.g., in
// ```
// let x: (Direction, Direction, bool) = ...;
// `(<direction-1>, <direction-2>, true)` - we are
// satisfied with `(_, _, true)`. In this case,
// `used_ctors` is empty.
- if is_non_exhaustive || missing_ctors.all_ctors_are_missing() {
+ if missing_ctors.all_ctors_are_missing() {
// All constructors are unused. Add a wild pattern
// rather than each individual constructor.
usefulness.apply_wildcard(pcx.ty)
) -> Usefulness<'tcx> {
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 matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
}
}
-/// 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 {
- FixedLenSlice(length) => (0..length).map(|_| ty).collect(),
- VarLenSlice(prefix, suffix) => (0..prefix + suffix).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,
// meaning all other types will compare unequal and thus equal patterns often do not cause the
// second pattern to lint about unreachable match arms.
/// fields filled with wild patterns.
fn specialize_one_pattern<'p, 'a: 'p, 'q: 'p, 'tcx>(
cx: &mut MatchCheckCtxt<'a, 'tcx>,
- pat: &'q Pat<'tcx>,
+ mut pat: &'q Pat<'tcx>,
constructor: &Constructor<'tcx>,
ctor_wild_subpatterns: &[&'p Pat<'tcx>],
) -> Option<PatStack<'p, 'tcx>> {
+ while let PatKind::AscribeUserType { ref subpattern, .. } = *pat.kind {
+ pat = subpattern;
+ }
+
+ if let NonExhaustive = constructor {
+ // Only a wildcard pattern can match the special extra constructor
+ return if pat.is_wildcard() { Some(PatStack::default()) } else { None };
+ }
+
let result = match *pat.kind {
- PatKind::AscribeUserType { ref subpattern, .. } => PatStack::from_pattern(subpattern)
- .specialize_constructor(cx, constructor, ctor_wild_subpatterns),
+ PatKind::AscribeUserType { .. } => bug!(), // Handled above
PatKind::Binding { .. } | PatKind::Wild => {
Some(PatStack::from_slice(ctor_wild_subpatterns))