parent
abae5e7e25
commit
04a92a1f56
@ -171,7 +171,7 @@ impl Constructor {
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Usefulness {
|
||||
Useful,
|
||||
UsefulWithWitness(Vec<P<Pat>>),
|
||||
UsefulWithWitness(Vec<Witness>),
|
||||
NotUseful
|
||||
}
|
||||
|
||||
@ -181,6 +181,13 @@ pub enum WitnessPreference {
|
||||
LeaveOutWitness
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct PatternContext<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
max_slice_length: usize,
|
||||
}
|
||||
|
||||
|
||||
fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
|
||||
let node = match value {
|
||||
&ConstVal::Bool(b) => ast::LitKind::Bool(b),
|
||||
@ -194,93 +201,126 @@ fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Constructs a partial witness for a pattern given a list of
|
||||
/// patterns expanded by the specialization step.
|
||||
///
|
||||
/// When a pattern P is discovered to be useful, this function is used bottom-up
|
||||
/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
|
||||
/// of values, V, where each value in that set is not covered by any previously
|
||||
/// used patterns and is covered by the pattern P'. Examples:
|
||||
///
|
||||
/// left_ty: tuple of 3 elements
|
||||
/// pats: [10, 20, _] => (10, 20, _)
|
||||
///
|
||||
/// left_ty: struct X { a: (bool, &'static str), b: usize}
|
||||
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
|
||||
fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
|
||||
pats: Vec<&Pat>, left_ty: Ty<'tcx>) -> P<Pat> {
|
||||
let pats_len = pats.len();
|
||||
let mut pats = pats.into_iter().map(|p| P((*p).clone()));
|
||||
let pat = match left_ty.sty {
|
||||
ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
|
||||
/// A stack of patterns in reverse order of construction
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Witness(Vec<P<Pat>>);
|
||||
|
||||
ty::TyAdt(adt, _) => {
|
||||
let v = ctor.variant_for_adt(adt);
|
||||
match v.ctor_kind {
|
||||
CtorKind::Fictive => {
|
||||
let field_pats: hir::HirVec<_> = v.fields.iter()
|
||||
.zip(pats)
|
||||
.filter(|&(_, ref pat)| pat.node != PatKind::Wild)
|
||||
.map(|(field, pat)| Spanned {
|
||||
span: DUMMY_SP,
|
||||
node: hir::FieldPat {
|
||||
name: field.name,
|
||||
pat: pat,
|
||||
is_shorthand: false,
|
||||
}
|
||||
}).collect();
|
||||
let has_more_fields = field_pats.len() < pats_len;
|
||||
PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields)
|
||||
impl Witness {
|
||||
pub fn single_pattern(&self) -> &Pat {
|
||||
assert_eq!(self.0.len(), 1);
|
||||
&self.0[0]
|
||||
}
|
||||
|
||||
fn push_wild_constructor<'a, 'tcx>(
|
||||
mut self,
|
||||
cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
ctor: &Constructor,
|
||||
ty: Ty<'tcx>)
|
||||
-> Self
|
||||
{
|
||||
let arity = constructor_arity(cx, ctor, ty);
|
||||
self.0.extend(repeat(DUMMY_WILD_PAT).take(arity).map(|p| P(p.clone())));
|
||||
self.apply_constructor(cx, ctor, ty)
|
||||
}
|
||||
|
||||
|
||||
/// Constructs a partial witness for a pattern given a list of
|
||||
/// patterns expanded by the specialization step.
|
||||
///
|
||||
/// When a pattern P is discovered to be useful, this function is used bottom-up
|
||||
/// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
|
||||
/// of values, V, where each value in that set is not covered by any previously
|
||||
/// used patterns and is covered by the pattern P'. Examples:
|
||||
///
|
||||
/// left_ty: tuple of 3 elements
|
||||
/// pats: [10, 20, _] => (10, 20, _)
|
||||
///
|
||||
/// left_ty: struct X { a: (bool, &'static str), b: usize}
|
||||
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
|
||||
fn apply_constructor<'a, 'tcx>(
|
||||
mut self,
|
||||
cx: &MatchCheckCtxt<'a,'tcx>,
|
||||
ctor: &Constructor,
|
||||
ty: Ty<'tcx>)
|
||||
-> Self
|
||||
{
|
||||
let arity = constructor_arity(cx, ctor, ty);
|
||||
let pat = {
|
||||
let len = self.0.len();
|
||||
let mut pats = self.0.drain(len-arity..).rev();
|
||||
|
||||
match ty.sty {
|
||||
ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None),
|
||||
|
||||
ty::TyAdt(adt, _) => {
|
||||
let v = ctor.variant_for_adt(adt);
|
||||
match v.ctor_kind {
|
||||
CtorKind::Fictive => {
|
||||
let field_pats: hir::HirVec<_> = v.fields.iter()
|
||||
.zip(pats)
|
||||
.filter(|&(_, ref pat)| pat.node != PatKind::Wild)
|
||||
.map(|(field, pat)| Spanned {
|
||||
span: DUMMY_SP,
|
||||
node: hir::FieldPat {
|
||||
name: field.name,
|
||||
pat: pat,
|
||||
is_shorthand: false,
|
||||
}
|
||||
}).collect();
|
||||
let has_more_fields = field_pats.len() < arity;
|
||||
PatKind::Struct(
|
||||
def_to_path(cx.tcx, v.did), field_pats, has_more_fields)
|
||||
}
|
||||
CtorKind::Fn => {
|
||||
PatKind::TupleStruct(
|
||||
def_to_path(cx.tcx, v.did), pats.collect(), None)
|
||||
}
|
||||
CtorKind::Const => {
|
||||
PatKind::Path(None, def_to_path(cx.tcx, v.did))
|
||||
}
|
||||
}
|
||||
}
|
||||
CtorKind::Fn => {
|
||||
PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None)
|
||||
|
||||
ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
|
||||
PatKind::Ref(pats.nth(0).unwrap(), mutbl)
|
||||
}
|
||||
CtorKind::Const => {
|
||||
PatKind::Path(None, def_to_path(cx.tcx, v.did))
|
||||
|
||||
ty::TySlice(_) | ty::TyArray(..) => {
|
||||
PatKind::Slice(pats.collect(), None, hir::HirVec::new())
|
||||
}
|
||||
|
||||
_ => {
|
||||
match *ctor {
|
||||
ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)),
|
||||
_ => PatKind::Wild,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ty::TyRef(_, ty::TypeAndMut { mutbl, .. }) => {
|
||||
assert_eq!(pats_len, 1);
|
||||
PatKind::Ref(pats.nth(0).unwrap(), mutbl)
|
||||
}
|
||||
self.0.push(P(hir::Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: pat,
|
||||
span: DUMMY_SP
|
||||
}));
|
||||
|
||||
ty::TySlice(_) => match ctor {
|
||||
&Slice(n) => {
|
||||
assert_eq!(pats_len, n);
|
||||
PatKind::Slice(pats.collect(), None, hir::HirVec::new())
|
||||
},
|
||||
_ => unreachable!()
|
||||
},
|
||||
|
||||
ty::TyArray(_, len) => {
|
||||
assert_eq!(pats_len, len);
|
||||
PatKind::Slice(pats.collect(), None, hir::HirVec::new())
|
||||
}
|
||||
|
||||
_ => {
|
||||
match *ctor {
|
||||
ConstantValue(ref v) => PatKind::Lit(const_val_to_expr(v)),
|
||||
_ => PatKind::Wild,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
P(hir::Pat {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: pat,
|
||||
span: DUMMY_SP
|
||||
})
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
|
||||
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
|
||||
let used_constructors: Vec<Constructor> = rows.iter()
|
||||
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
|
||||
/// Return the set of constructors from the same type as the first column of `matrix`,
|
||||
/// that are matched only by wildcard patterns from that 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 the return value.
|
||||
fn missing_constructors(cx: &MatchCheckCtxt, matrix: &Matrix,
|
||||
pcx: PatternContext) -> Vec<Constructor> {
|
||||
let used_constructors: Vec<Constructor> =
|
||||
matrix.0.iter()
|
||||
.flat_map(|row| pat_constructors(cx, row[0], pcx).unwrap_or(vec![]))
|
||||
.collect();
|
||||
all_constructors(cx, left_ty, max_slice_length)
|
||||
.into_iter()
|
||||
all_constructors(cx, pcx).into_iter()
|
||||
.filter(|c| !used_constructors.contains(c))
|
||||
.collect()
|
||||
}
|
||||
@ -289,13 +329,12 @@ fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
|
||||
/// values of type `left_ty`. For vectors, this would normally be an infinite set
|
||||
/// but is instead bounded by the maximum fixed length of slice patterns in
|
||||
/// the column of patterns being analyzed.
|
||||
fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
|
||||
max_slice_length: usize) -> Vec<Constructor> {
|
||||
match left_ty.sty {
|
||||
fn all_constructors(_cx: &MatchCheckCtxt, pcx: PatternContext) -> Vec<Constructor> {
|
||||
match pcx.ty.sty {
|
||||
ty::TyBool =>
|
||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||
ty::TySlice(_) =>
|
||||
(0..max_slice_length+1).map(|length| Slice(length)).collect(),
|
||||
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect(),
|
||||
ty::TyAdt(def, _) if def.is_enum() =>
|
||||
def.variants.iter().map(|v| Variant(v.did)).collect(),
|
||||
_ => vec![Single]
|
||||
@ -324,7 +363,9 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
debug!("is_useful({:?}, {:?})", matrix, v);
|
||||
if rows.is_empty() {
|
||||
return match witness {
|
||||
ConstructWitness => UsefulWithWitness(vec!()),
|
||||
ConstructWitness => UsefulWithWitness(vec![Witness(
|
||||
repeat(DUMMY_WILD_PAT).take(v.len()).map(|p| P(p.clone())).collect()
|
||||
)]),
|
||||
LeaveOutWitness => Useful
|
||||
};
|
||||
}
|
||||
@ -332,44 +373,37 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
return NotUseful;
|
||||
}
|
||||
assert!(rows.iter().all(|r| r.len() == v.len()));
|
||||
let left_ty = match rows.iter().filter_map(|r| r[0].pattern_ty).next()
|
||||
.or_else(|| v[0].pattern_ty)
|
||||
{
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
// all patterns are wildcards - we can pick any type we want
|
||||
cx.tcx.types.bool
|
||||
}
|
||||
|
||||
let pcx = PatternContext {
|
||||
ty: match rows.iter().filter_map(|r| r[0].pattern_ty).next()
|
||||
.or_else(|| v[0].pattern_ty)
|
||||
{
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
// all patterns are wildcards - we can pick any type we want
|
||||
cx.tcx.types.bool
|
||||
}
|
||||
},
|
||||
max_slice_length: rows.iter().filter_map(|row| match row[0].pat.node {
|
||||
PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
|
||||
_ => None
|
||||
}).max().map_or(0, |v| v + 1)
|
||||
};
|
||||
|
||||
let max_slice_length = rows.iter().filter_map(|row| match row[0].pat.node {
|
||||
PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
|
||||
_ => None
|
||||
}).max().map_or(0, |v| v + 1);
|
||||
debug!("is_useful: pcx={:?}, expanding {:?}", pcx, v[0]);
|
||||
|
||||
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
|
||||
debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors,
|
||||
left_ty);
|
||||
if constructors.is_empty() {
|
||||
let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
|
||||
if let Some(constructors) = pat_constructors(cx, v[0], pcx) {
|
||||
debug!("is_useful - expanding constructors: {:?}", constructors);
|
||||
constructors.into_iter().map(|c|
|
||||
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
|
||||
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
||||
} else {
|
||||
debug!("is_useful - expanding wildcard");
|
||||
let constructors = missing_constructors(cx, matrix, pcx);
|
||||
debug!("is_useful - missing_constructors = {:?}", constructors);
|
||||
if constructors.is_empty() {
|
||||
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
|
||||
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
|
||||
UsefulWithWitness(pats) => UsefulWithWitness({
|
||||
let arity = constructor_arity(cx, &c, left_ty);
|
||||
let mut result = {
|
||||
let pat_slice = &pats[..];
|
||||
let subpats: Vec<_> = (0..arity).map(|i| {
|
||||
pat_slice.get(i).map_or(DUMMY_WILD_PAT, |p| &**p)
|
||||
}).collect();
|
||||
vec![construct_witness(cx, &c, subpats, left_ty)]
|
||||
};
|
||||
result.extend(pats.into_iter().skip(arity));
|
||||
result
|
||||
}),
|
||||
result => result
|
||||
}
|
||||
all_constructors(cx, pcx).into_iter().map(|c| {
|
||||
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
|
||||
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
||||
} else {
|
||||
let matrix = rows.iter().filter_map(|r| {
|
||||
@ -380,21 +414,15 @@ pub fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
}).collect();
|
||||
match is_useful(cx, &matrix, &v[1..], witness) {
|
||||
UsefulWithWitness(pats) => {
|
||||
let mut new_pats: Vec<_> = constructors.into_iter().map(|constructor| {
|
||||
let arity = constructor_arity(cx, &constructor, left_ty);
|
||||
let wild_pats = vec![DUMMY_WILD_PAT; arity];
|
||||
construct_witness(cx, &constructor, wild_pats, left_ty)
|
||||
}).collect();
|
||||
new_pats.extend(pats);
|
||||
UsefulWithWitness(new_pats)
|
||||
},
|
||||
UsefulWithWitness(pats.into_iter().flat_map(|witness| {
|
||||
constructors.iter().map(move |ctor| {
|
||||
witness.clone().push_wild_constructor(cx, ctor, pcx.ty)
|
||||
})
|
||||
}).collect())
|
||||
}
|
||||
result => result
|
||||
}
|
||||
}
|
||||
} else {
|
||||
constructors.into_iter().map(|c|
|
||||
is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness)
|
||||
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,7 +439,14 @@ fn is_useful_specialized<'a, 'tcx>(
|
||||
specialize(cx, &r[..], &ctor, 0, arity)
|
||||
}).collect());
|
||||
match specialize(cx, v, &ctor, 0, arity) {
|
||||
Some(v) => is_useful(cx, &matrix, &v[..], witness),
|
||||
Some(v) => match is_useful(cx, &matrix, &v[..], witness) {
|
||||
UsefulWithWitness(witnesses) => UsefulWithWitness(
|
||||
witnesses.into_iter()
|
||||
.map(|witness| witness.apply_constructor(cx, &ctor, lty))
|
||||
.collect()
|
||||
),
|
||||
result => result
|
||||
},
|
||||
None => NotUseful
|
||||
}
|
||||
}
|
||||
@ -423,41 +458,43 @@ fn is_useful_specialized<'a, 'tcx>(
|
||||
/// Slice patterns, however, can match slices of different lengths. For instance,
|
||||
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
|
||||
///
|
||||
/// On the other hand, a wild pattern and an identifier pattern cannot be
|
||||
/// specialized in any way.
|
||||
fn pat_constructors(cx: &MatchCheckCtxt, p: Pattern,
|
||||
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
|
||||
/// Returns None in case of a catch-all, which can't be specialized.
|
||||
fn pat_constructors(cx: &MatchCheckCtxt,
|
||||
p: Pattern,
|
||||
pcx: PatternContext)
|
||||
-> Option<Vec<Constructor>>
|
||||
{
|
||||
let pat = p.as_raw();
|
||||
match pat.node {
|
||||
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
|
||||
match cx.tcx.expect_def(pat.id) {
|
||||
Def::Variant(id) | Def::VariantCtor(id, _) => vec![Variant(id)],
|
||||
Def::Variant(id) | Def::VariantCtor(id, _) => Some(vec![Variant(id)]),
|
||||
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
|
||||
Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
|
||||
Def::TyAlias(..) | Def::AssociatedTy(..) => Some(vec![Single]),
|
||||
Def::Const(..) | Def::AssociatedConst(..) =>
|
||||
span_bug!(p.span(), "const pattern should've been rewritten"),
|
||||
def => span_bug!(p.span(), "pat_constructors: unexpected definition {:?}", def),
|
||||
},
|
||||
PatKind::Lit(ref expr) =>
|
||||
vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
|
||||
Some(vec![ConstantValue(eval_const_expr(cx.tcx, &expr))]),
|
||||
PatKind::Range(ref lo, ref hi) =>
|
||||
vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))],
|
||||
Some(vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))]),
|
||||
PatKind::Slice(ref before, ref slice, ref after) =>
|
||||
match left_ty.sty {
|
||||
ty::TyArray(..) => vec![Single],
|
||||
match pcx.ty.sty {
|
||||
ty::TyArray(..) => Some(vec![Single]),
|
||||
ty::TySlice(_) if slice.is_some() => {
|
||||
(before.len() + after.len()..max_slice_length+1)
|
||||
.map(|length| Slice(length))
|
||||
.collect()
|
||||
Some((before.len() + after.len()..pcx.max_slice_length+1)
|
||||
.map(|length| Slice(length))
|
||||
.collect())
|
||||
}
|
||||
ty::TySlice(_) => vec!(Slice(before.len() + after.len())),
|
||||
ty::TySlice(_) => Some(vec!(Slice(before.len() + after.len()))),
|
||||
_ => span_bug!(pat.span, "pat_constructors: unexpected \
|
||||
slice pattern type {:?}", left_ty)
|
||||
slice pattern type {:?}", pcx.ty)
|
||||
},
|
||||
PatKind::Box(..) | PatKind::Tuple(..) | PatKind::Ref(..) =>
|
||||
vec![Single],
|
||||
Some(vec![Single]),
|
||||
PatKind::Binding(..) | PatKind::Wild =>
|
||||
vec![],
|
||||
None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,7 +503,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Pattern,
|
||||
///
|
||||
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
||||
/// A struct pattern's arity is the number of fields it contains, etc.
|
||||
pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
|
||||
debug!("constructor_arity({:?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs) => fs.len(),
|
||||
@ -685,7 +722,7 @@ fn specialize<'a, 'b, 'tcx>(
|
||||
|
||||
pub fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F)
|
||||
-> Option<A> where
|
||||
F: FnOnce(&Pat) -> A,
|
||||
F: FnOnce(&Witness) -> A,
|
||||
{
|
||||
let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
|
||||
match is_useful(cx, &pats, &[DUMMY_WILD_PATTERN], ConstructWitness) {
|
||||
|
@ -297,7 +297,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
let witnesses = if pats.is_empty() {
|
||||
vec![DUMMY_WILD_PAT]
|
||||
} else {
|
||||
pats.iter().map(|w| &**w).collect()
|
||||
pats.iter().map(|w| w.single_pattern()).collect()
|
||||
};
|
||||
match source {
|
||||
hir::MatchSource::ForLoopDesugar => {
|
||||
@ -484,7 +484,7 @@ fn check_irrefutable(cx: &MatchCheckCtxt, pat: &Pat, is_fn_arg: bool) {
|
||||
};
|
||||
|
||||
is_refutable(cx, pat, |uncovered_pat| {
|
||||
let pattern_string = pat_to_string(uncovered_pat);
|
||||
let pattern_string = pat_to_string(uncovered_pat.single_pattern());
|
||||
struct_span_err!(cx.tcx.sess, pat.span, E0005,
|
||||
"refutable pattern in {}: `{}` not covered",
|
||||
origin,
|
||||
|
53
src/test/ui/check_match/issue-35609.rs
Normal file
53
src/test/ui/check_match/issue-35609.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum Enum {
|
||||
A, B, C, D, E, F
|
||||
}
|
||||
use Enum::*;
|
||||
|
||||
struct S(Enum, ());
|
||||
struct Sd { x: Enum, y: () }
|
||||
|
||||
fn main() {
|
||||
match (A, ()) {
|
||||
(A, _) => {}
|
||||
}
|
||||
|
||||
match (A, A) {
|
||||
(_, A) => {}
|
||||
}
|
||||
|
||||
match ((A, ()), ()) {
|
||||
((A, ()), _) => {}
|
||||
}
|
||||
|
||||
match ((A, ()), A) {
|
||||
((A, ()), _) => {}
|
||||
}
|
||||
|
||||
match ((A, ()), ()) {
|
||||
((A, _), _) => {}
|
||||
}
|
||||
|
||||
|
||||
match S(A, ()) {
|
||||
S(A, _) => {}
|
||||
}
|
||||
|
||||
match (Sd { x: A, y: () }) {
|
||||
Sd { x: A, y: _ } => {}
|
||||
}
|
||||
|
||||
match Some(A) {
|
||||
Some(A) => (),
|
||||
None => ()
|
||||
}
|
||||
}
|
50
src/test/ui/check_match/issue-35609.stderr
Normal file
50
src/test/ui/check_match/issue-35609.stderr
Normal file
@ -0,0 +1,50 @@
|
||||
error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:20:11
|
||||
|
|
||||
20 | match (A, ()) {
|
||||
| ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
|
||||
--> $DIR/issue-35609.rs:24:11
|
||||
|
|
||||
24 | match (A, A) {
|
||||
| ^^^^^^ patterns `(A, B)`, `(B, B)`, `(C, B)` and 27 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:28:11
|
||||
|
|
||||
28 | match ((A, ()), ()) {
|
||||
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:32:11
|
||||
|
|
||||
32 | match ((A, ()), A) {
|
||||
| ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:36:11
|
||||
|
|
||||
36 | match ((A, ()), ()) {
|
||||
| ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:41:11
|
||||
|
|
||||
41 | match S(A, ()) {
|
||||
| ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:45:11
|
||||
|
|
||||
45 | match (Sd { x: A, y: () }) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered
|
||||
|
||||
error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
|
||||
--> $DIR/issue-35609.rs:49:11
|
||||
|
|
||||
49 | match Some(A) {
|
||||
| ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user