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