]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/_match.rs
Rename ty_param_bounds_and_ty to Polytype
[rust.git] / src / librustc / middle / typeck / 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 #![allow(non_camel_case_types)]
12
13 use middle::def;
14 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
15 use middle::subst;
16 use middle::subst::Subst;
17 use middle::ty;
18 use middle::typeck::check::demand;
19 use middle::typeck::check::{check_expr, check_expr_has_type, FnCtxt};
20 use middle::typeck::check::{instantiate_path, lookup_def};
21 use middle::typeck::check::{structure_of, valid_range_bounds};
22 use middle::typeck::infer;
23 use middle::typeck::require_same_types;
24
25 use std::collections::{HashMap, HashSet};
26 use std::gc::Gc;
27 use syntax::ast;
28 use syntax::ast_util;
29 use syntax::parse::token;
30 use syntax::codemap::Span;
31 use syntax::print::pprust;
32
33 pub fn check_match(fcx: &FnCtxt,
34                    expr: &ast::Expr,
35                    discrim: &ast::Expr,
36                    arms: &[ast::Arm]) {
37     let tcx = fcx.ccx.tcx;
38
39     let discrim_ty = fcx.infcx().next_ty_var();
40     check_expr_has_type(fcx, discrim, discrim_ty);
41
42     // Typecheck the patterns first, so that we get types for all the
43     // bindings.
44     for arm in arms.iter() {
45         let mut pcx = pat_ctxt {
46             fcx: fcx,
47             map: pat_id_map(&tcx.def_map, &**arm.pats.get(0)),
48         };
49
50         for p in arm.pats.iter() { check_pat(&mut pcx, &**p, discrim_ty);}
51     }
52
53     // The result of the match is the common supertype of all the
54     // arms. Start out the value as bottom, since it's the, well,
55     // bottom the type lattice, and we'll be moving up the lattice as
56     // we process each arm. (Note that any match with 0 arms is matching
57     // on any empty type and is therefore unreachable; should the flow
58     // of execution reach it, we will fail, so bottom is an appropriate
59     // type in that case)
60     let mut result_ty = ty::mk_bot();
61
62     // Now typecheck the blocks.
63     let mut saw_err = ty::type_is_error(discrim_ty);
64     for arm in arms.iter() {
65         let mut guard_err = false;
66         let mut guard_bot = false;
67         match arm.guard {
68           Some(ref e) => {
69               check_expr_has_type(fcx, &**e, ty::mk_bool());
70               let e_ty = fcx.expr_ty(&**e);
71               if ty::type_is_error(e_ty) {
72                   guard_err = true;
73               }
74               else if ty::type_is_bot(e_ty) {
75                   guard_bot = true;
76               }
77           },
78           None => ()
79         }
80         check_expr(fcx, &*arm.body);
81         let bty = fcx.node_ty(arm.body.id);
82         saw_err = saw_err || ty::type_is_error(bty);
83         if guard_err {
84             fcx.write_error(arm.body.id);
85             saw_err = true;
86         }
87         else if guard_bot {
88             fcx.write_bot(arm.body.id);
89         }
90
91         result_ty =
92             infer::common_supertype(
93                 fcx.infcx(),
94                 infer::MatchExpressionArm(expr.span, arm.body.span),
95                 true, // result_ty is "expected" here
96                 result_ty,
97                 bty);
98     }
99
100     if saw_err {
101         result_ty = ty::mk_err();
102     } else if ty::type_is_bot(discrim_ty) {
103         result_ty = ty::mk_bot();
104     }
105
106     fcx.write_ty(expr.id, result_ty);
107 }
108
109 pub struct pat_ctxt<'a> {
110     pub fcx: &'a FnCtxt<'a>,
111     pub map: PatIdMap,
112 }
113
114 pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
115                          subpats: &Option<Vec<Gc<ast::Pat>>>, expected: ty::t) {
116
117     // Typecheck the path.
118     let fcx = pcx.fcx;
119     let tcx = pcx.fcx.ccx.tcx;
120
121     let arg_types: Vec<ty::t> ;
122     let kind_name;
123
124     // structure_of requires type variables to be resolved.
125     // So when we pass in <expected>, it's an error if it
126     // contains type variables.
127
128     // Check to see whether this is an enum or a struct.
129     match *structure_of(pcx.fcx, pat.span, expected) {
130         ty::ty_enum(expected_def_id, ref expected_substs) => {
131             // Lookup the enum and variant def ids:
132             let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
133             match v_def.variant_def_ids() {
134                 Some((enm, var)) => {
135                     // Assign the pattern the type of the *enum*, not the variant.
136                     let enum_pty = ty::lookup_item_type(tcx, enm);
137                     instantiate_path(pcx.fcx,
138                                      path,
139                                      enum_pty,
140                                      v_def,
141                                      pat.span,
142                                      pat.id);
143
144                     // check that the type of the value being matched is a subtype
145                     // of the type of the pattern:
146                     let pat_ty = fcx.node_ty(pat.id);
147                     demand::subtype(fcx, pat.span, expected, pat_ty);
148
149                     // Get the expected types of the arguments.
150                     arg_types = {
151                         let vinfo =
152                             ty::enum_variant_with_id(tcx, enm, var);
153                         if enm == expected_def_id {
154                             vinfo.args.iter()
155                                 .map(|t| t.subst(tcx, expected_substs))
156                                 .collect()
157                         } else {
158                             vinfo.args.iter()
159                                 .map(|_| ty::mk_err())
160                                 .collect()
161                         }
162                     };
163
164                     kind_name = "variant";
165                 }
166                 None => {
167                     // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
168                     fcx.infcx().type_error_message_str_with_expected(pat.span,
169                                                        |expected, actual| {
170                        expected.map_or("".to_string(), |e| {
171                         format!("mismatched types: expected `{}` but found {}",
172                                 e, actual)
173                         })},
174                         Some(expected),
175                         "a structure pattern".to_string(),
176                         None);
177                     fcx.write_error(pat.id);
178                     kind_name = "[error]";
179                     arg_types = subpats.clone()
180                                        .unwrap_or_default()
181                                        .move_iter()
182                                        .map(|_| ty::mk_err())
183                                        .collect();
184                 }
185             }
186         }
187         ty::ty_struct(struct_def_id, ref expected_substs) => {
188             // Lookup the struct ctor def id
189             let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
190             let s_def_id = s_def.def_id();
191
192             // Assign the pattern the type of the struct.
193             let ctor_pty = ty::lookup_item_type(tcx, s_def_id);
194             let struct_pty = if ty::is_fn_ty(ctor_pty.ty) {
195                 ty::Polytype {ty: ty::ty_fn_ret(ctor_pty.ty),
196                               ..ctor_pty}
197             } else {
198                 ctor_pty
199             };
200             instantiate_path(pcx.fcx,
201                              path,
202                              struct_pty,
203                              s_def,
204                              pat.span,
205                              pat.id);
206
207             // Check that the type of the value being matched is a subtype of
208             // the type of the pattern.
209             let pat_ty = fcx.node_ty(pat.id);
210             demand::subtype(fcx, pat.span, expected, pat_ty);
211
212             // Get the expected types of the arguments.
213             let class_fields = ty::struct_fields(
214                 tcx, struct_def_id, expected_substs);
215             arg_types = class_fields.iter().map(|field| field.mt.ty).collect();
216
217             kind_name = "structure";
218         }
219         _ => {
220             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
221             fcx.infcx().type_error_message_str_with_expected(pat.span,
222                                                |expected, actual| {
223                                                expected.map_or("".to_string(),
224                                                               |e| {
225                         format!("mismatched types: expected `{}` but found {}",
226                                 e, actual)
227                     })
228                 },
229                 Some(expected),
230                 "an enum or structure pattern".to_string(),
231                 None);
232             fcx.write_error(pat.id);
233             kind_name = "[error]";
234             arg_types = subpats.clone()
235                                .unwrap_or_default()
236                                .iter()
237                                .map(|_| ty::mk_err())
238                                .collect();
239         }
240     }
241
242     let arg_len = arg_types.len();
243
244     // Count the number of subpatterns.
245     let subpats_len;
246     match *subpats {
247         None => subpats_len = arg_len,
248         Some(ref subpats) => subpats_len = subpats.len()
249     }
250
251     let mut error_happened = false;
252
253     if arg_len > 0 {
254         // N-ary variant.
255         if arg_len != subpats_len {
256             let s = format!("this pattern has {} field{}, \
257                              but the corresponding {} has {} field{}",
258                          subpats_len,
259                          if subpats_len == 1 {""} else {"s"},
260                          kind_name,
261                          arg_len,
262                          if arg_len == 1 {""} else {"s"});
263             tcx.sess.span_err(pat.span, s.as_slice());
264             error_happened = true;
265         }
266
267         if !error_happened {
268             for pats in subpats.iter() {
269                 for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
270                     check_pat(pcx, &**subpat, *arg_ty);
271                 }
272             }
273         }
274     } else if subpats_len > 0 {
275         tcx.sess.span_err(pat.span,
276                           format!("this pattern has {} field{}, \
277                                    but the corresponding {} has no fields",
278                                subpats_len,
279                                if subpats_len == 1 {""} else {"s"},
280                                kind_name).as_slice());
281         error_happened = true;
282     }
283
284     if error_happened {
285         for pats in subpats.iter() {
286             for pat in pats.iter() {
287                 check_pat(pcx, &**pat, ty::mk_err());
288             }
289         }
290     }
291 }
292
293 /// `path` is the AST path item naming the type of this struct.
294 /// `fields` is the field patterns of the struct pattern.
295 /// `class_fields` describes the type of each field of the struct.
296 /// `class_id` is the ID of the struct.
297 /// `substitutions` are the type substitutions applied to this struct type
298 /// (e.g. K,V in HashMap<K,V>).
299 /// `etc` is true if the pattern said '...' and false otherwise.
300 pub fn check_struct_pat_fields(pcx: &pat_ctxt,
301                                span: Span,
302                                fields: &[ast::FieldPat],
303                                class_fields: Vec<ty::field_ty>,
304                                class_id: ast::DefId,
305                                substitutions: &subst::Substs,
306                                etc: bool) {
307     let tcx = pcx.fcx.ccx.tcx;
308
309     // Index the class fields. The second argument in the tuple is whether the
310     // field has been bound yet or not.
311     let mut field_map = HashMap::new();
312     for (i, class_field) in class_fields.iter().enumerate() {
313         field_map.insert(class_field.name, (i, false));
314     }
315
316     // Typecheck each field.
317     let mut found_fields = HashSet::new();
318     for field in fields.iter() {
319         match field_map.find_mut(&field.ident.name) {
320             Some(&(_, true)) => {
321                 tcx.sess.span_err(span,
322                     format!("field `{}` bound twice in pattern",
323                             token::get_ident(field.ident)).as_slice());
324             }
325             Some(&(index, ref mut used)) => {
326                 *used = true;
327                 let class_field = *class_fields.get(index);
328                 let field_type = ty::lookup_field_type(tcx,
329                                                        class_id,
330                                                        class_field.id,
331                                                        substitutions);
332                 check_pat(pcx, &*field.pat, field_type);
333                 found_fields.insert(index);
334             }
335             None => {
336                 // Check the pattern anyway, so that attempts to look
337                 // up its type won't fail
338                 check_pat(pcx, &*field.pat, ty::mk_err());
339                 tcx.sess.span_err(span,
340                     format!("struct `{}` does not have a field named `{}`",
341                             ty::item_path_str(tcx, class_id),
342                             token::get_ident(field.ident)).as_slice());
343             }
344         }
345     }
346
347     // Report an error if not all the fields were specified.
348     if !etc {
349         for (i, field) in class_fields.iter().enumerate() {
350             if found_fields.contains(&i) {
351                 continue;
352             }
353
354             tcx.sess
355                .span_err(span,
356                          format!("pattern does not mention field `{}`",
357                                  token::get_name(field.name)).as_slice());
358         }
359     }
360 }
361
362 pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: Span,
363                         expected: ty::t, path: &ast::Path,
364                         fields: &[ast::FieldPat], etc: bool,
365                         struct_id: ast::DefId,
366                         substitutions: &subst::Substs) {
367     let fcx = pcx.fcx;
368     let tcx = pcx.fcx.ccx.tcx;
369
370     let class_fields = ty::lookup_struct_fields(tcx, struct_id);
371
372     // Check to ensure that the struct is the one specified.
373     match tcx.def_map.borrow().find(&pat_id) {
374         Some(&def::DefStruct(supplied_def_id))
375                 if supplied_def_id == struct_id => {
376             // OK.
377         }
378         Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => {
379             let name = pprust::path_to_str(path);
380             tcx.sess
381                .span_err(span,
382                          format!("mismatched types: expected `{}` but found \
383                                   `{}`",
384                                  fcx.infcx().ty_to_str(expected),
385                                  name).as_slice());
386         }
387         _ => {
388             tcx.sess.span_bug(span, "resolve didn't write in struct ID");
389         }
390     }
391
392     check_struct_pat_fields(pcx, span, fields, class_fields, struct_id,
393                             substitutions, etc);
394 }
395
396 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
397                                           pat_id: ast::NodeId,
398                                           span: Span,
399                                           expected: ty::t,
400                                           path: &ast::Path,
401                                           fields: &[ast::FieldPat],
402                                           etc: bool,
403                                           enum_id: ast::DefId,
404                                           substitutions: &subst::Substs) {
405     let fcx = pcx.fcx;
406     let tcx = pcx.fcx.ccx.tcx;
407
408     // Find the variant that was specified.
409     match tcx.def_map.borrow().find(&pat_id) {
410         Some(&def::DefVariant(found_enum_id, variant_id, _))
411                 if found_enum_id == enum_id => {
412             // Get the struct fields from this struct-like enum variant.
413             let class_fields = ty::lookup_struct_fields(tcx, variant_id);
414
415             check_struct_pat_fields(pcx, span, fields, class_fields,
416                                     variant_id, substitutions, etc);
417         }
418         Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => {
419             let name = pprust::path_to_str(path);
420             tcx.sess.span_err(span,
421                               format!("mismatched types: expected `{}` but \
422                                        found `{}`",
423                                       fcx.infcx().ty_to_str(expected),
424                                       name).as_slice());
425         }
426         _ => {
427             tcx.sess.span_bug(span, "resolve didn't write in variant");
428         }
429     }
430 }
431
432 // Pattern checking is top-down rather than bottom-up so that bindings get
433 // their types immediately.
434 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
435     let fcx = pcx.fcx;
436     let tcx = pcx.fcx.ccx.tcx;
437
438     match pat.node {
439       ast::PatWild | ast::PatWildMulti => {
440         fcx.write_ty(pat.id, expected);
441       }
442       ast::PatLit(ref lt) => {
443         check_expr_has_type(fcx, &**lt, expected);
444         fcx.write_ty(pat.id, fcx.expr_ty(&**lt));
445       }
446       ast::PatRange(ref begin, ref end) => {
447         check_expr_has_type(fcx, &**begin, expected);
448         check_expr_has_type(fcx, &**end, expected);
449         let b_ty =
450             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**begin));
451         let e_ty =
452             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**end));
453         debug!("pat_range beginning type: {:?}", b_ty);
454         debug!("pat_range ending type: {:?}", e_ty);
455         if !require_same_types(
456             tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
457             || "mismatched types in range".to_string())
458         {
459             // no-op
460         } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
461             tcx.sess.span_err(pat.span,
462                 "only char and numeric types are allowed in range");
463         } else {
464             match valid_range_bounds(fcx.ccx, &**begin, &**end) {
465                 Some(false) => {
466                     tcx.sess.span_err(begin.span,
467                         "lower range bound must be less than upper");
468                 },
469                 None => {
470                     tcx.sess.span_err(begin.span,
471                         "mismatched types in range");
472                 },
473                 _ => { },
474             }
475         }
476         fcx.write_ty(pat.id, b_ty);
477       }
478       ast::PatEnum(..) |
479       ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
480         let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
481         let const_pty = ty::lookup_item_type(tcx, const_did);
482         demand::suptype(fcx, pat.span, expected, const_pty.ty);
483         fcx.write_ty(pat.id, const_pty.ty);
484       }
485       ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
486         let typ = fcx.local_ty(pat.span, pat.id);
487
488         match bm {
489           ast::BindByRef(mutbl) => {
490             // if the binding is like
491             //    ref x | ref const x | ref mut x
492             // then the type of x is &M T where M is the mutability
493             // and T is the expected type
494             let region_var =
495                 fcx.infcx().next_region_var(
496                     infer::PatternRegion(pat.span));
497             let mt = ty::mt {ty: expected, mutbl: mutbl};
498             let region_ty = ty::mk_rptr(tcx, region_var, mt);
499             demand::eqtype(fcx, pat.span, region_ty, typ);
500           }
501           // otherwise the type of x is the expected type T
502           ast::BindByValue(_) => {
503             demand::eqtype(fcx, pat.span, expected, typ);
504           }
505         }
506
507         let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
508         if canon_id != pat.id {
509             let ct = fcx.local_ty(pat.span, canon_id);
510             demand::eqtype(fcx, pat.span, ct, typ);
511         }
512         fcx.write_ty(pat.id, typ);
513
514         debug!("(checking match) writing type for pat id {}", pat.id);
515
516         match sub {
517           Some(ref p) => check_pat(pcx, &**p, expected),
518           _ => ()
519         }
520       }
521       ast::PatIdent(_, ref path, _) => {
522         check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
523       }
524       ast::PatEnum(ref path, ref subpats) => {
525         check_pat_variant(pcx, pat, path, subpats, expected);
526       }
527       ast::PatStruct(ref path, ref fields, etc) => {
528         // Grab the class data that we care about.
529         let structure = structure_of(fcx, pat.span, expected);
530         let mut error_happened = false;
531         match *structure {
532             ty::ty_struct(cid, ref substs) => {
533                 check_struct_pat(pcx, pat.id, pat.span, expected, path,
534                                  fields.as_slice(), etc, cid, substs);
535             }
536             ty::ty_enum(eid, ref substs) => {
537                 check_struct_like_enum_variant_pat(pcx,
538                                                    pat.id,
539                                                    pat.span,
540                                                    expected,
541                                                    path,
542                                                    fields.as_slice(),
543                                                    etc,
544                                                    eid,
545                                                    substs);
546             }
547             _ => {
548                // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
549                 fcx.infcx().type_error_message_str_with_expected(pat.span,
550                                                                 |expected, actual| {
551                             expected.map_or("".to_string(),
552                                             |e| {
553                                 format!("mismatched types: expected \
554                                         `{}` but found {}", e, actual)
555                             })},
556                             Some(expected),
557                             "a structure pattern".to_string(),
558                             None);
559                 match tcx.def_map.borrow().find(&pat.id) {
560                     Some(&def::DefStruct(supplied_def_id)) => {
561                          check_struct_pat(pcx,
562                                           pat.id,
563                                           pat.span,
564                                           ty::mk_err(),
565                                           path,
566                                           fields.as_slice(),
567                                           etc,
568                                           supplied_def_id,
569                                           &subst::Substs::empty());
570                     }
571                     _ => () // Error, but we're already in an error case
572                 }
573                 error_happened = true;
574             }
575         }
576
577         // Finally, write in the type.
578         if error_happened {
579             fcx.write_error(pat.id);
580         } else {
581             fcx.write_ty(pat.id, expected);
582         }
583       }
584       ast::PatTup(ref elts) => {
585         let s = structure_of(fcx, pat.span, expected);
586         let e_count = elts.len();
587         match *s {
588             ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
589                 for (i, elt) in elts.iter().enumerate() {
590                     check_pat(pcx, &**elt, *ex_elts.get(i));
591                 }
592                 fcx.write_ty(pat.id, expected);
593             }
594             _ => {
595                 for elt in elts.iter() {
596                     check_pat(pcx, &**elt, ty::mk_err());
597                 }
598                 // use terr_tuple_size if both types are tuples
599                 let type_error = match *s {
600                     ty::ty_tup(ref ex_elts) => {
601                         ty::terr_tuple_size(ty::expected_found {
602                             expected: ex_elts.len(),
603                             found: e_count
604                         })
605                     }
606                     _ => ty::terr_mismatch
607                 };
608                 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
609                 fcx.infcx().type_error_message_str_with_expected(pat.span,
610                                                                  |expected,
611                                                                   actual| {
612                         expected.map_or("".to_string(), |e| {
613                             format!("mismatched types: expected `{}` \
614                                      but found {}", e, actual)
615                         }
616                     )},
617                     Some(expected),
618                     "tuple".to_string(),
619                     Some(&type_error));
620                 fcx.write_error(pat.id);
621             }
622         }
623       }
624       ast::PatBox(ref inner) => {
625           check_pointer_pat(pcx, Send, &**inner, pat.id, pat.span, expected);
626       }
627       ast::PatRegion(ref inner) => {
628           check_pointer_pat(pcx, Borrowed, &**inner, pat.id, pat.span, expected);
629       }
630       ast::PatVec(ref before, slice, ref after) => {
631         let default_region_var =
632             fcx.infcx().next_region_var(
633                 infer::PatternRegion(pat.span));
634
635         let check_err = |found: String| {
636             for &elt in before.iter() {
637                 check_pat(pcx, &*elt, ty::mk_err());
638             }
639             for elt in slice.iter() {
640                 check_pat(pcx, &**elt, ty::mk_err());
641             }
642             for elt in after.iter() {
643                 check_pat(pcx, &**elt, ty::mk_err());
644             }
645             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
646             fcx.infcx().type_error_message_str_with_expected(
647                 pat.span,
648                 |expected, actual| {
649                     expected.map_or("".to_string(),
650                                     |e| {
651                         format!("mismatched types: expected `{}` but found {}",
652                                 e, actual)
653                     })
654                 },
655                 Some(expected),
656                 found,
657                 None);
658             fcx.write_error(pat.id);
659         };
660
661         let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
662                                                                 pat.span,
663                                                                 expected) {
664           ty::ty_vec(mt, Some(fixed)) =>
665             (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
666           ty::ty_uniq(t) => match ty::get(t).sty {
667               ty::ty_vec(mt, None) => {
668                   fcx.type_error_message(pat.span,
669                                          |_| {
670                                             "unique vector patterns are no \
671                                              longer supported".to_string()
672                                          },
673                                          expected,
674                                          None);
675                   (mt.ty, default_region_var, ast::MutImmutable, None)
676               }
677               _ => {
678                   check_err("a vector pattern".to_string());
679                   return;
680               }
681           },
682           ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
683               ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
684               _ => {
685                   check_err("a vector pattern".to_string());
686                   return;
687               }
688           },
689           _ => {
690               check_err("a vector pattern".to_string());
691               return;
692           }
693         };
694
695         let min_len = before.len() + after.len();
696         fixed.and_then(|count| match slice {
697             Some(_) if count < min_len =>
698                 Some(format!("a fixed vector pattern of size at least {}", min_len)),
699
700             None if count != min_len =>
701                 Some(format!("a fixed vector pattern of size {}", min_len)),
702
703             _ => None
704         }).map(check_err);
705
706         for elt in before.iter() {
707             check_pat(pcx, &**elt, elt_type);
708         }
709         match slice {
710             Some(ref slice_pat) => {
711                 let slice_ty = ty::mk_slice(tcx,
712                                             region_var,
713                                             ty::mt {ty: elt_type, mutbl: mutbl});
714                 check_pat(pcx, &**slice_pat, slice_ty);
715             }
716             None => ()
717         }
718         for elt in after.iter() {
719             check_pat(pcx, &**elt, elt_type);
720         }
721         fcx.write_ty(pat.id, expected);
722       }
723
724       ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
725     }
726 }
727
728 // Helper function to check gc, box and & patterns
729 pub fn check_pointer_pat(pcx: &pat_ctxt,
730                          pointer_kind: PointerKind,
731                          inner: &ast::Pat,
732                          pat_id: ast::NodeId,
733                          span: Span,
734                          expected: ty::t) {
735     let fcx = pcx.fcx;
736     let check_inner: |ty::t| = |e_inner| {
737         check_pat(pcx, inner, e_inner);
738         fcx.write_ty(pat_id, expected);
739     };
740     match *structure_of(fcx, span, expected) {
741         ty::ty_uniq(e_inner) if pointer_kind == Send && !ty::type_is_trait(e_inner) => {
742             check_inner(e_inner);
743         }
744         ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed && !ty::type_is_trait(e_inner.ty) => {
745             check_inner(e_inner.ty);
746         }
747         _ => {
748             check_pat(pcx, inner, ty::mk_err());
749             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
750             fcx.infcx().type_error_message_str_with_expected(
751                 span,
752                 |expected, actual| {
753                     expected.map_or("".to_string(), |e| {
754                         format!("mismatched types: expected `{}` but found {}",
755                                 e, actual)
756                     })
757                 },
758                 Some(expected),
759                 format!("{} pattern", match pointer_kind {
760                     Send => "a box",
761                     Borrowed => "an `&`-pointer",
762                 }),
763                 None);
764             fcx.write_error(pat_id);
765           }
766     }
767 }
768
769 #[deriving(PartialEq)]
770 pub enum PointerKind {
771     Send,
772     Borrowed,
773 }
774