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