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