let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(DefLocal(..)) = def {
+ if let Some(Def::Local(..)) = def {
if edef.variants.iter().any(|variant|
variant.name == ident.node.unhygienic_name
&& variant.kind() == VariantKind::Unit
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: hir::MatchSource) {
match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) {
UsefulWithWitness(pats) => {
- let witness = match &pats[..] {
- [ref witness] => &**witness,
- [] => DUMMY_WILD_PAT,
- _ => unreachable!()
+ let witnesses = if pats.is_empty() {
+ vec![DUMMY_WILD_PAT]
+ } else {
+ pats.iter().map(|w| &**w ).collect()
};
match source {
hir::MatchSource::ForLoopDesugar => {
- // `witness` has the form `Some(<head>)`, peel off the `Some`
- let witness = match witness.node {
+ // `witnesses[0]` has the form `Some(<head>)`, peel off the `Some`
+ let witness = match witnesses[0].node {
hir::PatEnum(_, Some(ref pats)) => match &pats[..] {
[ref pat] => &**pat,
_ => unreachable!(),
},
_ => unreachable!(),
};
-
span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
pat_to_string(witness));
},
_ => {
+ let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
+ pat_to_string(w)
+ }).collect();
+ const LIMIT: usize = 3;
+ let joined_patterns = match pattern_strings.len() {
+ 0 => unreachable!(),
+ 1 => format!("`{}`", pattern_strings[0]),
+ 2...LIMIT => {
+ let (tail, head) = pattern_strings.split_last().unwrap();
+ format!("`{}`", head.join("`, `") + "` and `" + tail)
+ },
+ _ => {
+ let (head, tail) = pattern_strings.split_at(LIMIT);
+ format!("`{}` and {} more", head.join("`, `"), tail.len())
+ }
+ };
span_err!(cx.tcx.sess, sp, E0004,
- "non-exhaustive patterns: `{}` not covered",
- pat_to_string(witness)
+ "non-exhaustive patterns: {} not covered",
+ joined_patterns
);
},
}
hir::PatIdent(..) | hir::PatEnum(..) | hir::PatQPath(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
match def {
- Some(DefAssociatedConst(did)) |
- Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did,
+ Some(Def::AssociatedConst(did)) |
+ Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
Some(pat.id), None) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
}
}
-fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
- left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
+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))
.collect();
all_constructors(cx, left_ty, max_slice_length)
.into_iter()
- .find(|c| !used_constructors.contains(c))
+ .filter(|c| !used_constructors.contains(c))
+ .collect()
}
/// This determines the set of all possible constructors of a pattern matching
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
if constructors.is_empty() {
- match missing_constructor(cx, matrix, left_ty, max_slice_length) {
- None => {
- 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
- }
- }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
- },
-
- Some(constructor) => {
- let matrix = rows.iter().filter_map(|r| {
- if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
- Some(r[1..].to_vec())
- } else {
- None
- }
- }).collect();
- match is_useful(cx, &matrix, &v[1..], witness) {
- UsefulWithWitness(pats) => {
- let arity = constructor_arity(cx, &constructor, left_ty);
- let wild_pats = vec![DUMMY_WILD_PAT; arity];
- let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
- let mut new_pats = vec![enum_pat];
- new_pats.extend(pats);
- UsefulWithWitness(new_pats)
- },
+ let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
+ 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
}
+ }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
+ } else {
+ let matrix = rows.iter().filter_map(|r| {
+ if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) {
+ Some(r[1..].to_vec())
+ } else {
+ None
+ }
+ }).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)
+ },
+ result => result
}
}
} else {
match pat.node {
hir::PatIdent(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefStruct(_)) => vec!(Single),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Struct(..)) => vec!(Single),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!()
},
hir::PatEnum(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatQPath(..) =>
been rewritten"),
hir::PatStruct(..) =>
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => vec!(Variant(id)),
+ Some(Def::Variant(_, id)) => vec!(Variant(id)),
_ => vec!(Single)
},
hir::PatLit(ref expr) =>
hir::PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
match opt_def {
- Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
+ Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
+ Some(Def::Variant(_, id)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
hir::PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
match def {
- DefConst(..) | DefAssociatedConst(..) =>
+ Def::Const(..) | Def::AssociatedConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
- DefVariant(_, id, _) if *constructor != Variant(id) => None,
- DefVariant(..) | DefStruct(..) => {
+ Def::Variant(_, id) if *constructor != Variant(id) => None,
+ Def::Variant(..) | Def::Struct(..) => {
Some(match args {
&Some(ref args) => args.iter().map(|p| &**p).collect(),
&None => vec![DUMMY_WILD_PAT; arity],
//FIXME: (@jroesch) this code should be floated up as well
let infcx = infer::new_infer_ctxt(cx.tcx,
&cx.tcx.tables,
- Some(cx.param_env.clone()),
- false);
+ Some(cx.param_env.clone()));
if infcx.type_moves_by_default(pat_ty, pat.span) {
check_move(p, sub.as_ref().map(|p| &**p));
}
let infcx = infer::new_infer_ctxt(cx.tcx,
&cx.tcx.tables,
- Some(checker.cx.param_env.clone()),
- false);
+ Some(checker.cx.param_env.clone()));
let mut visitor = ExprUseVisitor::new(&mut checker, &infcx);
visitor.walk_expr(guard);