]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/_match.rs
rollup merge of #17355 : gamazeps/issue17210
[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 syntax::ast;
28 use syntax::ast_util;
29 use syntax::parse::token;
30 use syntax::codemap::Span;
31 use syntax::print::pprust;
32 use syntax::ptr::P;
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, 'tcx: 'a> {
111     pub fcx: &'a FnCtxt<'a, 'tcx>,
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<P<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 `{}`, 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                                        .into_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 `{}`, 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).clone();
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, span: Span,
359                         fields: &[ast::FieldPat], etc: bool,
360                         struct_id: ast::DefId,
361                         substitutions: &subst::Substs) {
362     let _fcx = pcx.fcx;
363     let tcx = pcx.fcx.ccx.tcx;
364
365     let class_fields = ty::lookup_struct_fields(tcx, struct_id);
366
367     check_struct_pat_fields(pcx, span, fields, class_fields, struct_id,
368                             substitutions, etc);
369 }
370
371 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
372                                           pat_id: ast::NodeId,
373                                           span: Span,
374                                           expected: ty::t,
375                                           path: &ast::Path,
376                                           fields: &[ast::FieldPat],
377                                           etc: bool,
378                                           enum_id: ast::DefId,
379                                           substitutions: &subst::Substs) {
380     let fcx = pcx.fcx;
381     let tcx = pcx.fcx.ccx.tcx;
382
383     // Find the variant that was specified.
384     match tcx.def_map.borrow().find(&pat_id) {
385         Some(&def::DefVariant(found_enum_id, variant_id, _))
386                 if found_enum_id == enum_id => {
387             // Get the struct fields from this struct-like enum variant.
388             let class_fields = ty::lookup_struct_fields(tcx, variant_id);
389
390             check_struct_pat_fields(pcx, span, fields, class_fields,
391                                     variant_id, substitutions, etc);
392         }
393         Some(&def::DefStruct(..)) |
394         Some(&def::DefVariant(..)) |
395         Some(&def::DefTy(..)) => {
396             let name = pprust::path_to_string(path);
397             span_err!(tcx.sess, span, E0028,
398                 "mismatched types: expected `{}`, found `{}`",
399                 fcx.infcx().ty_to_string(expected), name);
400         }
401         _ => {
402             tcx.sess.span_bug(span, "resolve didn't write in variant");
403         }
404     }
405 }
406
407 // Pattern checking is top-down rather than bottom-up so that bindings get
408 // their types immediately.
409 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
410     let fcx = pcx.fcx;
411     let tcx = pcx.fcx.ccx.tcx;
412
413     match pat.node {
414       ast::PatWild(_) => {
415         fcx.write_ty(pat.id, expected);
416       }
417       ast::PatLit(ref lt) => {
418         check_expr_has_type(fcx, &**lt, expected);
419         fcx.write_ty(pat.id, fcx.expr_ty(&**lt));
420       }
421       ast::PatRange(ref begin, ref end) => {
422         check_expr_has_type(fcx, &**begin, expected);
423         check_expr_has_type(fcx, &**end, expected);
424         let b_ty =
425             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**begin));
426         let e_ty =
427             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**end));
428         debug!("pat_range beginning type: {:?}", b_ty);
429         debug!("pat_range ending type: {:?}", e_ty);
430         if !require_same_types(
431             tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
432             || "mismatched types in range".to_string())
433         {
434             // no-op
435         } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
436             span_err!(tcx.sess, begin.span, E0029,
437                 "only char and numeric types are allowed in range");
438         } else {
439             match valid_range_bounds(fcx.ccx, &**begin, &**end) {
440                 Some(false) => {
441                     span_err!(tcx.sess, begin.span, E0030,
442                         "lower range bound must be less than upper");
443                 },
444                 None => {
445                     span_err!(tcx.sess, begin.span, E0031,
446                         "mismatched types in range");
447                 },
448                 _ => { },
449             }
450         }
451         fcx.write_ty(pat.id, b_ty);
452       }
453       ast::PatEnum(..) |
454       ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
455         let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
456         let const_pty = ty::lookup_item_type(tcx, const_did);
457         demand::suptype(fcx, pat.span, expected, const_pty.ty);
458         fcx.write_ty(pat.id, const_pty.ty);
459       }
460       ast::PatIdent(bm, ref path1, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
461         let typ = fcx.local_ty(pat.span, pat.id);
462
463         match bm {
464           ast::BindByRef(mutbl) => {
465             // if the binding is like
466             //    ref x | ref const x | ref mut x
467             // then the type of x is &M T where M is the mutability
468             // and T is the expected type
469             let region_var =
470                 fcx.infcx().next_region_var(
471                     infer::PatternRegion(pat.span));
472             let mt = ty::mt {ty: expected, mutbl: mutbl};
473             let region_ty = ty::mk_rptr(tcx, region_var, mt);
474             demand::eqtype(fcx, pat.span, region_ty, typ);
475           }
476           // otherwise the type of x is the expected type T
477           ast::BindByValue(_) => {
478             demand::eqtype(fcx, pat.span, expected, typ);
479           }
480         }
481
482         let canon_id = *pcx.map.get(&path1.node);
483         if canon_id != pat.id {
484             let ct = fcx.local_ty(pat.span, canon_id);
485             demand::eqtype(fcx, pat.span, ct, typ);
486         }
487         fcx.write_ty(pat.id, typ);
488
489         debug!("(checking match) writing type {} (expected {}) for pat id {}",
490                ppaux::ty_to_string(tcx, typ),
491                ppaux::ty_to_string(tcx, expected),
492                pat.id);
493
494         match *sub {
495             Some(ref p) => check_pat(pcx, &**p, expected),
496             _ => ()
497         }
498       }
499       // it's not a binding, it's an enum in disguise:
500       ast::PatIdent(_, ref path1, _) => {
501         let path = ast_util::ident_to_path(path1.span,path1.node);
502         check_pat_variant(pcx, pat, &path, &Some(Vec::new()), expected);
503       }
504       ast::PatEnum(ref path, ref subpats) => {
505         check_pat_variant(pcx, pat, path, subpats, expected);
506       }
507       ast::PatStruct(ref path, ref fields, etc) => {
508         // Grab the class data that we care about.
509         let structure = structure_of(fcx, pat.span, expected);
510         let mut error_happened = false;
511         match *structure {
512             ty::ty_struct(cid, ref substs) => {
513                 // Verify that the pattern named the right structure.
514                 let item_did = tcx.def_map.borrow().get(&pat.id).def_id();
515                 match ty::ty_to_def_id(ty::lookup_item_type(tcx, item_did).ty) {
516                     Some(struct_did) if struct_did != cid => {
517                         span_err!(tcx.sess, path.span, E0032,
518                                   "`{}` does not name the structure `{}`",
519                                   pprust::path_to_string(path),
520                                   fcx.infcx().ty_to_string(expected));
521                     },
522                     Some(_) => {},
523                     None => {
524                         tcx.sess.span_bug(
525                             path.span,
526                             format!("This shouldn't happen: failed to lookup structure. \
527                                 item_did = {}", item_did).as_slice())
528                     },
529                 }
530
531                 check_struct_pat(pcx, pat.span, fields.as_slice(), etc, cid, substs);
532             }
533             ty::ty_enum(eid, ref substs) => {
534                 check_struct_like_enum_variant_pat(pcx,
535                                                    pat.id,
536                                                    pat.span,
537                                                    expected,
538                                                    path,
539                                                    fields.as_slice(),
540                                                    etc,
541                                                    eid,
542                                                    substs);
543             }
544             _ => {
545                // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
546                 fcx.infcx().type_error_message_str_with_expected(pat.span,
547                                                                 |expected, actual| {
548                             expected.map_or("".to_string(),
549                                             |e| {
550                                 format!("mismatched types: expected \
551                                         `{}`, found {}", e, actual)
552                             })},
553                             Some(expected),
554                             "a structure pattern".to_string(),
555                             None);
556                 match tcx.def_map.borrow().find(&pat.id) {
557                     Some(def) => {
558                         let struct_ty = fcx.instantiate_item_type(pat.span, def.def_id());
559                         check_struct_pat(pcx, pat.span, fields.as_slice(),
560                                          etc, def.def_id(), &struct_ty.substs);
561                     }
562                     None => {
563                         tcx.sess.span_bug(pat.span,
564                                           "whoops, looks like resolve didn't \
565                                            write a def in here")
566                     }
567                 }
568                 error_happened = true;
569             }
570         }
571
572         // Finally, write in the type.
573         if error_happened {
574             fcx.write_error(pat.id);
575         } else {
576             fcx.write_ty(pat.id, expected);
577         }
578       }
579       ast::PatTup(ref elts) => {
580         let s = structure_of(fcx, pat.span, expected);
581         let e_count = elts.len();
582         match *s {
583             ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
584                 for (i, elt) in elts.iter().enumerate() {
585                     check_pat(pcx, &**elt, *ex_elts.get(i));
586                 }
587                 fcx.write_ty(pat.id, expected);
588             }
589             _ => {
590                 for elt in elts.iter() {
591                     check_pat(pcx, &**elt, ty::mk_err());
592                 }
593                 // use terr_tuple_size if both types are tuples
594                 let type_error = match *s {
595                     ty::ty_tup(ref ex_elts) => {
596                         ty::terr_tuple_size(ty::expected_found {
597                             expected: ex_elts.len(),
598                             found: e_count
599                         })
600                     }
601                     _ => ty::terr_mismatch
602                 };
603                 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
604                 fcx.infcx().type_error_message_str_with_expected(pat.span,
605                                                                  |expected,
606                                                                   actual| {
607                         expected.map_or("".to_string(), |e| {
608                             format!("mismatched types: expected `{}`, \
609                                      found {}", e, actual)
610                         }
611                     )},
612                     Some(expected),
613                     "tuple".to_string(),
614                     Some(&type_error));
615                 fcx.write_error(pat.id);
616             }
617         }
618       }
619       ast::PatBox(ref inner) => {
620           check_pointer_pat(pcx, Send, &**inner, pat.id, pat.span, expected);
621       }
622       ast::PatRegion(ref inner) => {
623           check_pointer_pat(pcx, Borrowed, &**inner, pat.id, pat.span, expected);
624       }
625       ast::PatVec(ref before, ref slice, ref after) => {
626         let default_region_var =
627             fcx.infcx().next_region_var(
628                 infer::PatternRegion(pat.span));
629
630         let check_err = |found: String| {
631             for elt in before.iter() {
632                 check_pat(pcx, &**elt, ty::mk_err());
633             }
634             for elt in slice.iter() {
635                 check_pat(pcx, &**elt, ty::mk_err());
636             }
637             for elt in after.iter() {
638                 check_pat(pcx, &**elt, ty::mk_err());
639             }
640             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
641             fcx.infcx().type_error_message_str_with_expected(
642                 pat.span,
643                 |expected, actual| {
644                     expected.map_or("".to_string(),
645                                     |e| {
646                         format!("mismatched types: expected `{}`, found {}",
647                                 e, actual)
648                     })
649                 },
650                 Some(expected),
651                 found,
652                 None);
653             fcx.write_error(pat.id);
654         };
655
656         let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
657                                                                 pat.span,
658                                                                 expected) {
659           ty::ty_vec(ty, Some(fixed)) =>
660             (ty, default_region_var, ast::MutImmutable, Some(fixed)),
661           ty::ty_uniq(t) => match ty::get(t).sty {
662               ty::ty_vec(ty, None) => {
663                   fcx.type_error_message(pat.span,
664                                          |_| {
665                                             "unique vector patterns are no \
666                                              longer supported".to_string()
667                                          },
668                                          expected,
669                                          None);
670                   (ty, default_region_var, ast::MutImmutable, None)
671               }
672               _ => {
673                   check_err("a vector pattern".to_string());
674                   return;
675               }
676           },
677           ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
678               ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None),
679               _ => {
680                   check_err("a vector pattern".to_string());
681                   return;
682               }
683           },
684           _ => {
685               check_err("a vector pattern".to_string());
686               return;
687           }
688         };
689
690         let min_len = before.len() + after.len();
691         fixed.and_then(|count| match *slice {
692             Some(_) if count < min_len =>
693                 Some(format!("a fixed vector pattern of size at least {}", min_len)),
694
695             None if count != min_len =>
696                 Some(format!("a fixed vector pattern of size {}", min_len)),
697
698             _ => None
699         }).map(check_err);
700
701         for elt in before.iter() {
702             check_pat(pcx, &**elt, elt_type);
703         }
704         match *slice {
705             Some(ref slice_pat) => {
706                 let slice_ty = ty::mk_slice(tcx,
707                                             region_var,
708                                             ty::mt {ty: elt_type, mutbl: mutbl});
709                 check_pat(pcx, &**slice_pat, slice_ty);
710             }
711             None => ()
712         }
713         for elt in after.iter() {
714             check_pat(pcx, &**elt, elt_type);
715         }
716         fcx.write_ty(pat.id, expected);
717       }
718
719       ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
720     }
721 }
722
723 // Helper function to check gc, box and & patterns
724 fn check_pointer_pat(pcx: &pat_ctxt,
725                      pointer_kind: PointerKind,
726                      inner: &ast::Pat,
727                      pat_id: ast::NodeId,
728                      span: Span,
729                      expected: ty::t) {
730     let fcx = pcx.fcx;
731     let tcx = fcx.ccx.tcx;
732     let check_inner: |ty::t| = |e_inner| {
733         match ty::get(e_inner).sty {
734             ty::ty_trait(_) if pat_is_binding(&tcx.def_map, inner) => {
735                 // This is "x = SomeTrait" being reduced from
736                 // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
737                 check_pat(pcx, inner, ty::mk_err());
738                 span_err!(tcx.sess, span, E0033,
739                     "type `{}` cannot be dereferenced",
740                     fcx.infcx().ty_to_string(expected));
741                 fcx.write_error(pat_id);
742             }
743             _ => {
744                 check_pat(pcx, inner, e_inner);
745                 fcx.write_ty(pat_id, expected);
746             }
747         }
748     };
749
750     match *structure_of(fcx, span, expected) {
751         ty::ty_uniq(e_inner) if pointer_kind == Send => {
752             check_inner(e_inner);
753         }
754         ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
755             check_inner(e_inner.ty);
756         }
757         _ => {
758             check_pat(pcx, inner, ty::mk_err());
759             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
760             fcx.infcx().type_error_message_str_with_expected(
761                 span,
762                 |expected, actual| {
763                     expected.map_or("".to_string(), |e| {
764                         format!("mismatched types: expected `{}`, found {}",
765                                 e, actual)
766                     })
767                 },
768                 Some(expected),
769                 format!("{} pattern", match pointer_kind {
770                     Send => "a box",
771                     Borrowed => "an `&`-pointer",
772                 }),
773                 None);
774             fcx.write_error(pat_id);
775           }
776     }
777 }
778
779 #[deriving(PartialEq)]
780 pub enum PointerKind {
781     Send,
782     Borrowed,
783 }
784