]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_match.rs
Change exhaustiveness analysis to permit multiple constructors per pattern
[rust.git] / src / librustc / middle / check_match.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use middle::const_eval::{compare_const_vals, const_bool, const_float, const_nil, const_val};
12 use middle::const_eval::{eval_const_expr, lookup_const_by_id};
13 use middle::def::*;
14 use middle::pat_util::*;
15 use middle::ty::*;
16 use middle::ty;
17 use std::fmt;
18 use std::gc::{Gc, GC};
19 use std::iter::AdditiveIterator;
20 use std::iter::range_inclusive;
21 use syntax::ast::*;
22 use syntax::ast_util::{is_unguarded, walk_pat};
23 use syntax::codemap::{Span, Spanned, DUMMY_SP};
24 use syntax::owned_slice::OwnedSlice;
25 use syntax::print::pprust::pat_to_str;
26 use syntax::visit;
27 use syntax::visit::{Visitor, FnKind};
28 use util::ppaux::ty_to_str;
29
30 struct Matrix(Vec<Vec<Gc<Pat>>>);
31
32 /// Pretty-printer for matrices of patterns, example:
33 /// ++++++++++++++++++++++++++
34 /// + _     + []             +
35 /// ++++++++++++++++++++++++++
36 /// + true  + [First]        +
37 /// ++++++++++++++++++++++++++
38 /// + true  + [Second(true)] +
39 /// ++++++++++++++++++++++++++
40 /// + false + [_]            +
41 /// ++++++++++++++++++++++++++
42 /// + _     + [_, _, ..tail] +
43 /// ++++++++++++++++++++++++++
44 impl fmt::Show for Matrix {
45     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46         try!(write!(f, "\n"));
47
48         let &Matrix(ref m) = self;
49         let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
50             row.iter().map(|&pat| pat_to_str(pat)).collect::<Vec<String>>()
51         }).collect();
52
53         let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0u);
54         assert!(m.iter().all(|row| row.len() == column_count));
55         let column_widths: Vec<uint> = range(0, column_count).map(|col| {
56             pretty_printed_matrix.iter().map(|row| row.get(col).len()).max().unwrap_or(0u)
57         }).collect();
58
59         let total_width = column_widths.iter().map(|n| *n).sum() + column_count * 3 + 1;
60         let br = String::from_char(total_width, '+');
61         try!(write!(f, "{}\n", br));
62         for row in pretty_printed_matrix.move_iter() {
63             try!(write!(f, "+"));
64             for (column, pat_str) in row.move_iter().enumerate() {
65                 try!(write!(f, " "));
66                 f.width = Some(*column_widths.get(column));
67                 try!(f.pad(pat_str.as_slice()));
68                 try!(write!(f, " +"));
69             }
70             try!(write!(f, "\n"));
71             try!(write!(f, "{}\n", br));
72         }
73         Ok(())
74     }
75 }
76
77 struct MatchCheckCtxt<'a> {
78     tcx: &'a ty::ctxt
79 }
80
81 #[deriving(Clone, PartialEq)]
82 enum Constructor {
83     /// The constructor of all patterns that don't vary by constructor,
84     /// e.g. struct patterns and fixed-length arrays.
85     Single,
86     /// Enum variants.
87     Variant(DefId),
88     /// Literal values.
89     ConstantValue(const_val),
90     /// Ranges of literal values (2..5).
91     ConstantRange(const_val, const_val),
92     /// Array patterns of length n.
93     Slice(uint)
94 }
95
96 #[deriving(Clone)]
97 enum Usefulness {
98     Useful(Vec<Gc<Pat>>),
99     NotUseful
100 }
101
102 enum WitnessPreference {
103     ConstructWitness,
104     LeaveOutWitness
105 }
106
107 impl Usefulness {
108     fn useful(self) -> Option<Vec<Gc<Pat>>> {
109         match self {
110             Useful(pats) => Some(pats),
111             _ => None
112         }
113     }
114 }
115
116 impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
117     fn visit_expr(&mut self, ex: &Expr, _: ()) {
118         check_expr(self, ex);
119     }
120     fn visit_local(&mut self, l: &Local, _: ()) {
121         check_local(self, l);
122     }
123     fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId, _: ()) {
124         check_fn(self, fk, fd, b, s);
125     }
126 }
127
128 pub fn check_crate(tcx: &ty::ctxt, krate: &Crate) {
129     let mut cx = MatchCheckCtxt { tcx: tcx, };
130
131     visit::walk_crate(&mut cx, krate, ());
132
133     tcx.sess.abort_if_errors();
134 }
135
136 fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
137     visit::walk_expr(cx, ex, ());
138     match ex.node {
139         ExprMatch(scrut, ref arms) => {
140             // First, check legality of move bindings.
141             for arm in arms.iter() {
142                 check_legality_of_move_bindings(cx,
143                                                 arm.guard.is_some(),
144                                                 arm.pats.as_slice());
145             }
146
147             // Second, check for unreachable arms.
148             check_arms(cx, arms.as_slice());
149
150             // Finally, check if the whole match expression is exhaustive.
151             // Check for empty enum, because is_useful only works on inhabited types.
152             let pat_ty = node_id_to_type(cx.tcx, scrut.id);
153             if (*arms).is_empty() {
154                if !type_is_empty(cx.tcx, pat_ty) {
155                    // We know the type is inhabited, so this must be wrong
156                    cx.tcx.sess.span_err(ex.span, format!("non-exhaustive patterns: \
157                                 type {} is non-empty",
158                                 ty_to_str(cx.tcx, pat_ty)).as_slice());
159                }
160                // If the type *is* empty, it's vacuously exhaustive
161                return;
162             }
163             let m: Matrix = Matrix(arms
164                 .iter()
165                 .filter(|&arm| is_unguarded(arm))
166                 .flat_map(|arm| arm.pats.iter())
167                 .map(|pat| vec!(pat.clone()))
168                 .collect());
169             check_exhaustive(cx, ex.span, &m);
170         },
171         _ => ()
172     }
173 }
174
175 // Check for unreachable patterns
176 fn check_arms(cx: &MatchCheckCtxt, arms: &[Arm]) {
177     let mut seen = Matrix(vec!());
178     for arm in arms.iter() {
179         for pat in arm.pats.iter() {
180             // Check that we do not match against a static NaN (#6804)
181             let pat_matches_nan: |&Pat| -> bool = |p| {
182                 let opt_def = cx.tcx.def_map.borrow().find_copy(&p.id);
183                 match opt_def {
184                     Some(DefStatic(did, false)) => {
185                         let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
186                         match eval_const_expr(cx.tcx, &*const_expr) {
187                             const_float(f) if f.is_nan() => true,
188                             _ => false
189                         }
190                     }
191                     _ => false
192                 }
193             };
194
195             walk_pat(&**pat, |p| {
196                 if pat_matches_nan(p) {
197                     cx.tcx.sess.span_warn(p.span, "unmatchable NaN in pattern, \
198                                                    use the is_nan method in a guard instead");
199                 }
200                 true
201             });
202
203             let v = vec!(*pat);
204             match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
205                 NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
206                 _ => ()
207             }
208             if arm.guard.is_none() {
209                 let Matrix(mut rows) = seen;
210                 rows.push(v);
211                 seen = Matrix(rows);
212             }
213         }
214     }
215 }
216
217 fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
218     match p.node {
219         PatIdent(_, _, Some(s)) => { raw_pat(s) }
220         _ => { p }
221     }
222 }
223
224 fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
225     match is_useful(cx, m, [wild()], ConstructWitness) {
226         Useful(pats) => {
227             let witness = match pats.as_slice() {
228                 [witness] => witness,
229                 [] => wild(),
230                 _ => unreachable!()
231             };
232             let msg = format!("non-exhaustive patterns: `{0}` not covered", pat_to_str(&*witness));
233             cx.tcx.sess.span_err(sp, msg.as_slice());
234         }
235         NotUseful => {
236             // This is good, wildcard pattern isn't reachable
237         }
238     }
239 }
240
241 fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
242     let node = match value {
243         &const_bool(b) => LitBool(b),
244         &const_nil => LitNil,
245         _ => unreachable!()
246     };
247     box (GC) Expr {
248         id: 0,
249         node: ExprLit(box(GC) Spanned { node: node, span: DUMMY_SP }),
250         span: DUMMY_SP
251     }
252 }
253
254 fn def_to_path(tcx: &ty::ctxt, id: DefId) -> Path {
255     ty::with_path(tcx, id, |mut path| Path {
256         global: false,
257         segments: path.last().map(|elem| PathSegment {
258             identifier: Ident::new(elem.name()),
259             lifetimes: vec!(),
260             types: OwnedSlice::empty()
261         }).move_iter().collect(),
262         span: DUMMY_SP,
263     })
264 }
265
266 /// Constructs a partial witness for a pattern given a list of
267 /// patterns expanded by the specialization step.
268 ///
269 /// When a pattern P is discovered to be useful, this function is used bottom-up
270 /// to reconstruct a complete witness, e.g. a pattern P' that covers a subset
271 /// of values, V, where each value in that set is not covered by any previously
272 /// used patterns and is covered by the pattern P'. Examples:
273 ///
274 /// left_ty: tuple of 3 elements
275 /// pats: [10, 20, _]           => (10, 20, _)
276 ///
277 /// left_ty: struct X { a: (bool, &'static str), b: uint}
278 /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
279 fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
280                      pats: Vec<Gc<Pat>>, left_ty: ty::t) -> Gc<Pat> {
281     let pat = match ty::get(left_ty).sty {
282         ty::ty_tup(_) => PatTup(pats),
283
284         ty::ty_enum(cid, _) | ty::ty_struct(cid, _)  => {
285             let (vid, is_structure) = match ctor {
286                 &Variant(vid) => (vid,
287                     ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
288                 _ => (cid, true)
289             };
290             if is_structure {
291                 let fields = ty::lookup_struct_fields(cx.tcx, vid);
292                 let field_pats = fields.move_iter()
293                     .zip(pats.iter())
294                     .map(|(field, pat)| FieldPat {
295                         ident: Ident::new(field.name),
296                         pat: pat.clone()
297                     }).collect();
298                 PatStruct(def_to_path(cx.tcx, vid), field_pats, false)
299             } else {
300                 PatEnum(def_to_path(cx.tcx, vid), Some(pats))
301             }
302         }
303
304         ty::ty_rptr(_, ty::mt { ty: ty, .. }) => {
305             match ty::get(ty).sty {
306                ty::ty_vec(_, Some(n)) => match ctor {
307                     &Single => {
308                         assert_eq!(pats.len(), n);
309                         PatVec(pats, None, vec!())
310                     },
311                     _ => unreachable!()
312                 },
313                 ty::ty_vec(_, None) => match ctor {
314                     &Slice(n) => {
315                         assert_eq!(pats.len(), n);
316                         PatVec(pats, None, vec!())
317                     },
318                     _ => unreachable!()
319                 },
320                 ty::ty_str => PatWild,
321
322                 _ => {
323                     assert_eq!(pats.len(), 1);
324                     PatRegion(pats.get(0).clone())
325                 }
326             }
327         }
328
329         ty::ty_box(_) => {
330             assert_eq!(pats.len(), 1);
331             PatBox(pats.get(0).clone())
332         }
333
334         ty::ty_vec(_, Some(len)) => {
335             assert_eq!(pats.len(), len);
336             PatVec(pats, None, vec!())
337         }
338
339         _ => {
340             match *ctor {
341                 ConstantValue(ref v) => PatLit(const_val_to_expr(v)),
342                 _ => PatWild
343             }
344         }
345     };
346
347     box (GC) Pat {
348         id: 0,
349         node: pat,
350         span: DUMMY_SP
351     }
352 }
353
354 fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
355                        left_ty: ty::t, max_slice_length: uint) -> Option<Constructor> {
356     let used_constructors: Vec<Constructor> = rows.iter()
357         .flat_map(|row| pat_constructors(cx, *row.get(0), left_ty, max_slice_length).move_iter())
358         .collect();
359     all_constructors(cx, left_ty, max_slice_length)
360         .move_iter()
361         .find(|c| !used_constructors.contains(c))
362 }
363
364 /// This determines the set of all possible constructors of a pattern matching
365 /// values of type `left_ty`. For vectors, this would normally be an infinite set
366 /// but is instead bounded by the maximum fixed length of slice patterns in
367 /// the column of patterns being analyzed.
368 fn all_constructors(cx: &MatchCheckCtxt, left_ty: ty::t,
369                     max_slice_length: uint) -> Vec<Constructor> {
370     match ty::get(left_ty).sty {
371         ty::ty_bool =>
372             [true, false].iter().map(|b| ConstantValue(const_bool(*b))).collect(),
373
374         ty::ty_nil =>
375             vec!(ConstantValue(const_nil)),
376
377         ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
378             ty::ty_vec(_, None) =>
379                 range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(),
380             _ => vec!(Single)
381         },
382
383         ty::ty_enum(eid, _) =>
384             ty::enum_variants(cx.tcx, eid)
385                 .iter()
386                 .map(|va| Variant(va.id))
387                 .collect(),
388
389         _ =>
390             vec!(Single)
391     }
392 }
393
394 // Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html
395 //
396 // Whether a vector `v` of patterns is 'useful' in relation to a set of such
397 // vectors `m` is defined as there being a set of inputs that will match `v`
398 // but not any of the sets in `m`.
399 //
400 // This is used both for reachability checking (if a pattern isn't useful in
401 // relation to preceding patterns, it is not reachable) and exhaustiveness
402 // checking (if a wildcard pattern is useful in relation to a matrix, the
403 // matrix isn't exhaustive).
404
405 // Note: is_useful doesn't work on empty types, as the paper notes.
406 // So it assumes that v is non-empty.
407 fn is_useful(cx: &MatchCheckCtxt, m @ &Matrix(ref rows): &Matrix,
408              v: &[Gc<Pat>], witness: WitnessPreference) -> Usefulness {
409     debug!("{:}", m);
410     if rows.len() == 0u {
411         return Useful(vec!());
412     }
413     if rows.get(0).len() == 0u {
414         return NotUseful;
415     }
416     let real_pat = match rows.iter().find(|r| r.get(0).id != 0) {
417         Some(r) => {
418             match r.get(0).node {
419                 // An arm of the form `ref x @ sub_pat` has type
420                 // `sub_pat`, not `&sub_pat` as `x` itself does.
421                 PatIdent(BindByRef(_), _, Some(sub)) => sub,
422                 _ => *r.get(0)
423             }
424         }
425         None if v.len() == 0 => return NotUseful,
426         None => v[0]
427     };
428     let left_ty = if real_pat.id == 0 {
429         ty::mk_nil()
430     } else {
431         ty::pat_ty(cx.tcx, &*real_pat)
432     };
433
434     let max_slice_length = rows.iter().filter_map(|row| match row.get(0).node {
435         PatVec(ref before, _, ref after) => Some(before.len() + after.len()),
436         _ => None
437     }).max().map_or(0, |v| v + 1);
438
439     let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
440     if constructors.is_empty() {
441         match missing_constructor(cx, m, left_ty, max_slice_length) {
442             None => {
443                 all_constructors(cx, left_ty, max_slice_length).move_iter().filter_map(|c| {
444                     is_useful_specialized(cx, m, v, c.clone(),
445                                           left_ty, witness).useful().map(|pats| {
446                         Useful(match witness {
447                             ConstructWitness => {
448                                 let arity = constructor_arity(cx, &c, left_ty);
449                                 let subpats = {
450                                     let pat_slice = pats.as_slice();
451                                     Vec::from_fn(arity, |i| {
452                                         pat_slice.get(i).map(|p| p.clone())
453                                             .unwrap_or_else(|| wild())
454                                     })
455                                 };
456                                 let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
457                                 result.extend(pats.move_iter().skip(arity));
458                                 result
459                             }
460                             LeaveOutWitness => vec!()
461                         })
462                     })
463                 }).nth(0).unwrap_or(NotUseful)
464             },
465
466             Some(constructor) => {
467                 let matrix = Matrix(rows.iter().filter_map(|r|
468                     default(cx, r.as_slice())).collect());
469                 match is_useful(cx, &matrix, v.tail(), witness) {
470                     Useful(pats) => Useful(match witness {
471                         ConstructWitness => {
472                             let arity = constructor_arity(cx, &constructor, left_ty);
473                             let wild_pats = Vec::from_elem(arity, wild());
474                             let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
475                             (vec!(enum_pat)).append(pats.as_slice())
476                         }
477                         LeaveOutWitness => vec!()
478                     }),
479                     result => result
480                 }
481             }
482         }
483     } else {
484         constructors.move_iter().filter_map(|c| {
485             is_useful_specialized(cx, m, v, c.clone(), left_ty, witness)
486                 .useful().map(|pats| Useful(pats))
487         }).nth(0).unwrap_or(NotUseful)
488     }
489 }
490
491 fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, v: &[Gc<Pat>],
492                          ctor: Constructor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
493     let arity = constructor_arity(cx, &ctor, lty);
494     let matrix = Matrix(m.iter().filter_map(|r| {
495         specialize(cx, r.as_slice(), &ctor, arity)
496     }).collect());
497     match specialize(cx, v, &ctor, arity) {
498         Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
499         None => NotUseful
500     }
501 }
502
503 /// Determines the constructors that the given pattern can be specialized to.
504 ///
505 /// In most cases, there's only one constructor that a specific pattern
506 /// represents, such as a specific enum variant or a specific literal value.
507 /// Slice patterns, however, can match slices of different lengths. For instance,
508 /// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
509 ///
510 /// On the other hand, a wild pattern and an identifier pattern cannot be
511 /// specialized in any way.
512 fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
513                     left_ty: ty::t, max_slice_length: uint) -> Vec<Constructor> {
514     let pat = raw_pat(p);
515     match pat.node {
516         PatIdent(..) =>
517             match cx.tcx.def_map.borrow().find(&pat.id) {
518                 Some(&DefStatic(did, false)) => {
519                     let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
520                     vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
521                 },
522                 Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
523                 _ => vec!()
524             },
525         PatEnum(..) =>
526             match cx.tcx.def_map.borrow().find(&pat.id) {
527                 Some(&DefStatic(did, false)) => {
528                     let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
529                     vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
530                 },
531                 Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
532                 _ => vec!(Single)
533             },
534         PatStruct(..) =>
535             match cx.tcx.def_map.borrow().find(&pat.id) {
536                 Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
537                 _ => vec!(Single)
538             },
539         PatLit(expr) =>
540             vec!(ConstantValue(eval_const_expr(cx.tcx, &*expr))),
541         PatRange(lo, hi) =>
542             vec!(ConstantRange(eval_const_expr(cx.tcx, &*lo), eval_const_expr(cx.tcx, &*hi))),
543         PatVec(ref before, ref slice, ref after) =>
544             match ty::get(left_ty).sty {
545                 ty::ty_vec(_, Some(_)) => vec!(Single),
546                 _                      => if slice.is_some() {
547                     range_inclusive(before.len() + after.len(), max_slice_length)
548                         .map(|length| Slice(length))
549                         .collect()
550                 } else {
551                     vec!(Slice(before.len() + after.len()))
552                 }
553             },
554         PatBox(_) | PatTup(_) | PatRegion(..) =>
555             vec!(Single),
556         PatWild | PatWildMulti =>
557             vec!(),
558         PatMac(_) =>
559             cx.tcx.sess.bug("unexpanded macro")
560     }
561 }
562
563 fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
564     let pat = raw_pat(p);
565     match pat.node {
566         PatWild | PatWildMulti => true,
567         PatIdent(_, _, _) =>
568             match cx.tcx.def_map.borrow().find(&pat.id) {
569                 Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
570                 _ => true
571             },
572         PatVec(ref before, Some(_), ref after) =>
573             before.is_empty() && after.is_empty(),
574         _ => false
575     }
576 }
577
578 /// This computes the arity of a constructor. The arity of a constructor
579 /// is how many subpattern patterns of that constructor should be expanded to.
580 ///
581 /// For instance, a tuple pattern (_, 42u, Some([])) has the arity of 3.
582 /// A struct pattern's arity is the number of fields it contains, etc.
583 fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
584     match ty::get(ty).sty {
585         ty::ty_tup(ref fs) => fs.len(),
586         ty::ty_box(_) | ty::ty_uniq(_) => 1u,
587         ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
588             ty::ty_vec(_, None) => match *ctor {
589                 Slice(length) => length,
590                 _ => unreachable!()
591             },
592             ty::ty_str => 0u,
593             _ => 1u
594         },
595         ty::ty_enum(eid, _) => {
596             match *ctor {
597                 Variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
598                 _ => unreachable!()
599             }
600         }
601         ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
602         ty::ty_vec(_, Some(n)) => n,
603         _ => 0u
604     }
605 }
606
607 fn range_covered_by_constructor(ctor: &Constructor,
608                                 from: &const_val,to: &const_val) -> Option<bool> {
609     let (c_from, c_to) = match *ctor {
610         ConstantValue(ref value)        => (value, value),
611         ConstantRange(ref from, ref to) => (from, to),
612         Single                          => return Some(true),
613         _                               => unreachable!()
614     };
615     let cmp_from = compare_const_vals(c_from, from);
616     let cmp_to = compare_const_vals(c_to, to);
617     match (cmp_from, cmp_to) {
618         (Some(val1), Some(val2)) => Some(val1 >= 0 && val2 <= 0),
619         _ => None
620     }
621 }
622
623 /// This is the main specialization step. It expands the first pattern in the given row
624 /// into `arity` patterns based on the constructor. For most patterns, the step is trivial,
625 /// for instance tuple patterns are flattened and box patterns expand into their inner pattern.
626 ///
627 /// OTOH, slice patterns with a subslice pattern (..tail) can be expanded into multiple
628 /// different patterns.
629 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
630 /// fields filled with wild patterns.
631 fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
632               constructor: &Constructor, arity: uint) -> Option<Vec<Gc<Pat>>> {
633     let &Pat {
634         id: pat_id, node: ref node, span: pat_span
635     } = &(*raw_pat(r[0]));
636     let head: Option<Vec<Gc<Pat>>> = match node {
637         &PatWild =>
638             Some(Vec::from_elem(arity, wild())),
639
640         &PatWildMulti =>
641             Some(Vec::from_elem(arity, wild())),
642
643         &PatIdent(_, _, _) => {
644             let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
645             match opt_def {
646                 Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
647                     Some(vec!())
648                 } else {
649                     None
650                 },
651                 Some(DefStatic(did, _)) => {
652                     let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
653                     let e_v = eval_const_expr(cx.tcx, &*const_expr);
654                     match range_covered_by_constructor(constructor, &e_v, &e_v) {
655                         Some(true) => Some(vec!()),
656                         Some(false) => None,
657                         None => {
658                             cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
659                             None
660                         }
661                     }
662                 }
663                 _ => {
664                     Some(Vec::from_elem(arity, wild()))
665                 }
666             }
667         }
668
669         &PatEnum(_, ref args) => {
670             let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
671             match def {
672                 DefStatic(did, _) => {
673                     let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
674                     let e_v = eval_const_expr(cx.tcx, &*const_expr);
675                     match range_covered_by_constructor(constructor, &e_v, &e_v) {
676                         Some(true) => Some(vec!()),
677                         Some(false) => None,
678                         None => {
679                             cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
680                             None
681                         }
682                     }
683                 }
684                 DefVariant(_, id, _) if *constructor != Variant(id) => None,
685                 DefVariant(..) | DefFn(..) | DefStruct(..) => {
686                     Some(match args {
687                         &Some(ref args) => args.clone(),
688                         &None => Vec::from_elem(arity, wild())
689                     })
690                 }
691                 _ => None
692             }
693         }
694
695         &PatStruct(_, ref pattern_fields, _) => {
696             // Is this a struct or an enum variant?
697             let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
698             let class_id = match def {
699                 DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
700                     Some(variant_id)
701                 } else {
702                     None
703                 },
704                 DefStruct(struct_id) => Some(struct_id),
705                 _ => None
706             };
707             class_id.map(|variant_id| {
708                 let struct_fields = ty::lookup_struct_fields(cx.tcx, variant_id);
709                 let args = struct_fields.iter().map(|sf| {
710                     match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
711                         Some(f) => f.pat,
712                         _ => wild()
713                     }
714                 }).collect();
715                 args
716             })
717         }
718
719         &PatTup(ref args) =>
720             Some(args.clone()),
721
722         &PatBox(ref inner) | &PatRegion(ref inner) =>
723             Some(vec!(inner.clone())),
724
725         &PatLit(ref expr) => {
726             let expr_value = eval_const_expr(cx.tcx, &**expr);
727             match range_covered_by_constructor(constructor, &expr_value, &expr_value) {
728                 Some(true) => Some(vec!()),
729                 Some(false) => None,
730                 None => {
731                     cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
732                     None
733                 }
734             }
735         }
736
737         &PatRange(ref from, ref to) => {
738             let from_value = eval_const_expr(cx.tcx, &**from);
739             let to_value = eval_const_expr(cx.tcx, &**to);
740             match range_covered_by_constructor(constructor, &from_value, &to_value) {
741                 Some(true) => Some(vec!()),
742                 Some(false) => None,
743                 None => {
744                     cx.tcx.sess.span_err(pat_span, "mismatched types between arms");
745                     None
746                 }
747             }
748         }
749
750         &PatVec(ref before, ref slice, ref after) => {
751             match *constructor {
752                 // Fixed-length vectors.
753                 Single => {
754                     let mut pats = before.clone();
755                     pats.grow_fn(arity - before.len() - after.len(), |_| wild());
756                     pats.push_all(after.as_slice());
757                     Some(pats)
758                 },
759                 Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
760                     let mut pats = before.clone();
761                     pats.grow_fn(arity - before.len() - after.len(), |_| wild());
762                     pats.push_all(after.as_slice());
763                     Some(pats)
764                 },
765                 Slice(length) if before.len() + after.len() == length => {
766                     let mut pats = before.clone();
767                     pats.push_all(after.as_slice());
768                     Some(pats)
769                 },
770                 _ => None
771             }
772         }
773
774         &PatMac(_) => {
775             cx.tcx.sess.span_err(pat_span, "unexpanded macro");
776             None
777         }
778     };
779     head.map(|head| head.append(r.tail()))
780 }
781
782 fn default(cx: &MatchCheckCtxt, r: &[Gc<Pat>]) -> Option<Vec<Gc<Pat>>> {
783     if is_wild(cx, r[0]) {
784         Some(Vec::from_slice(r.tail()))
785     } else {
786         None
787     }
788 }
789
790 fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
791     visit::walk_local(cx, loc, ());
792
793     let name = match loc.source {
794         LocalLet => "local",
795         LocalFor => "`for` loop"
796     };
797
798     match is_refutable(cx, loc.pat) {
799         Some(pat) => {
800             let msg = format!(
801                 "refutable pattern in {} binding: `{}` not covered",
802                 name, pat_to_str(&*pat)
803             );
804             cx.tcx.sess.span_err(loc.pat.span, msg.as_slice());
805         },
806         None => ()
807     }
808
809     // Check legality of move bindings.
810     check_legality_of_move_bindings(cx, false, [ loc.pat ]);
811 }
812
813 fn check_fn(cx: &mut MatchCheckCtxt,
814             kind: &FnKind,
815             decl: &FnDecl,
816             body: &Block,
817             sp: Span) {
818     visit::walk_fn(cx, kind, decl, body, sp, ());
819     for input in decl.inputs.iter() {
820         match is_refutable(cx, input.pat) {
821             Some(pat) => {
822                 let msg = format!(
823                     "refutable pattern in function argument: `{}` not covered",
824                     pat_to_str(&*pat)
825                 );
826                 cx.tcx.sess.span_err(input.pat.span, msg.as_slice());
827             },
828             None => ()
829         }
830         check_legality_of_move_bindings(cx, false, [input.pat]);
831     }
832 }
833
834 fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
835     let pats = Matrix(vec!(vec!(pat)));
836     is_useful(cx, &pats, [wild()], ConstructWitness)
837         .useful()
838         .map(|pats| {
839             assert_eq!(pats.len(), 1);
840             pats.get(0).clone()
841         })
842 }
843
844 // Legality of move bindings checking
845
846 fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
847                                    has_guard: bool,
848                                    pats: &[Gc<Pat>]) {
849     let tcx = cx.tcx;
850     let def_map = &tcx.def_map;
851     let mut by_ref_span = None;
852     for pat in pats.iter() {
853         pat_bindings(def_map, &**pat, |bm, _, span, _path| {
854             match bm {
855                 BindByRef(_) => {
856                     by_ref_span = Some(span);
857                 }
858                 BindByValue(_) => {
859                 }
860             }
861         })
862     }
863
864     let check_move: |&Pat, Option<Gc<Pat>>| = |p, sub| {
865         // check legality of moving out of the enum
866
867         // x @ Foo(..) is legal, but x @ Foo(y) isn't.
868         if sub.map_or(false, |p| pat_contains_bindings(def_map, &*p)) {
869             tcx.sess.span_err(
870                 p.span,
871                 "cannot bind by-move with sub-bindings");
872         } else if has_guard {
873             tcx.sess.span_err(
874                 p.span,
875                 "cannot bind by-move into a pattern guard");
876         } else if by_ref_span.is_some() {
877             tcx.sess.span_err(
878                 p.span,
879                 "cannot bind by-move and by-ref \
880                  in the same pattern");
881             tcx.sess.span_note(
882                 by_ref_span.unwrap(),
883                 "by-ref binding occurs here");
884         }
885     };
886
887     for pat in pats.iter() {
888         walk_pat(&**pat, |p| {
889             if pat_is_binding(def_map, &*p) {
890                 match p.node {
891                     PatIdent(BindByValue(_), _, sub) => {
892                         let pat_ty = ty::node_id_to_type(tcx, p.id);
893                         if ty::type_moves_by_default(tcx, pat_ty) {
894                             check_move(p, sub);
895                         }
896                     }
897                     PatIdent(BindByRef(_), _, _) => {
898                     }
899                     _ => {
900                         cx.tcx.sess.span_bug(
901                             p.span,
902                             format!("binding pattern {} is not an \
903                                      identifier: {:?}",
904                                     p.id,
905                                     p.node).as_slice());
906                     }
907                 }
908             }
909             true
910         });
911     }
912 }