]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/typeck/check/_match.rs
3d37de38e4523eba450b9ddc34a62703cf524a9e
[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_strbuf!("mismatched types: expected `{}` but \
171                                         found {}",
172                                        e,
173                                        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 = ast_util::def_id_of_def(s_def);
192
193             // Assign the pattern the type of the struct.
194             let ctor_tpt = ty::lookup_item_type(tcx, s_def_id);
195             let struct_tpt = if ty::is_fn_ty(ctor_tpt.ty) {
196                 ty::ty_param_bounds_and_ty {ty: ty::ty_fn_ret(ctor_tpt.ty),
197                                         ..ctor_tpt}
198             } else {
199                 ctor_tpt
200             };
201             instantiate_path(pcx.fcx,
202                              path,
203                              struct_tpt,
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_strbuf!("mismatched types: expected `{}` but \
227                                         found {}",
228                                        e,
229                                        actual)
230                     })
231                 },
232                 Some(expected),
233                 "an enum or structure pattern".to_string(),
234                 None);
235             fcx.write_error(pat.id);
236             kind_name = "[error]";
237             arg_types = subpats.clone()
238                                .unwrap_or_default()
239                                .iter()
240                                .map(|_| ty::mk_err())
241                                .collect();
242         }
243     }
244
245     let arg_len = arg_types.len();
246
247     // Count the number of subpatterns.
248     let subpats_len;
249     match *subpats {
250         None => subpats_len = arg_len,
251         Some(ref subpats) => subpats_len = subpats.len()
252     }
253
254     let mut error_happened = false;
255
256     if arg_len > 0 {
257         // N-ary variant.
258         if arg_len != subpats_len {
259             let s = format!("this pattern has \
260                              {npat, plural, =1{# field} other{# fields}}, \
261                              but the corresponding {kind} has \
262                              {narg, plural, =1{# field} other{# fields}}",
263                          npat = subpats_len,
264                          kind = kind_name,
265                          narg = arg_len);
266             tcx.sess.span_err(pat.span, s.as_slice());
267             error_happened = true;
268         }
269
270         if !error_happened {
271             for pats in subpats.iter() {
272                 for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
273                     check_pat(pcx, *subpat, *arg_ty);
274                 }
275             }
276         }
277     } else if subpats_len > 0 {
278         tcx.sess.span_err(pat.span,
279                           format!("this pattern has \
280                                    {npat, plural, =1{# field} other{# fields}}, \
281                                    but the corresponding {kind} has no fields",
282                                npat = subpats_len,
283                                kind = kind_name).as_slice());
284         error_happened = true;
285     }
286
287     if error_happened {
288         for pats in subpats.iter() {
289             for pat in pats.iter() {
290                 check_pat(pcx, *pat, ty::mk_err());
291             }
292         }
293     }
294 }
295
296 /// `path` is the AST path item naming the type of this struct.
297 /// `fields` is the field patterns of the struct pattern.
298 /// `class_fields` describes the type of each field of the struct.
299 /// `class_id` is the ID of the struct.
300 /// `substitutions` are the type substitutions applied to this struct type
301 /// (e.g. K,V in HashMap<K,V>).
302 /// `etc` is true if the pattern said '...' and false otherwise.
303 pub fn check_struct_pat_fields(pcx: &pat_ctxt,
304                                span: Span,
305                                path: &ast::Path,
306                                fields: &[ast::FieldPat],
307                                class_fields: Vec<ty::field_ty> ,
308                                class_id: ast::DefId,
309                                substitutions: &ty::substs,
310                                etc: bool) {
311     let tcx = pcx.fcx.ccx.tcx;
312
313     // Index the class fields. The second argument in the tuple is whether the
314     // field has been bound yet or not.
315     let mut field_map = HashMap::new();
316     for (i, class_field) in class_fields.iter().enumerate() {
317         field_map.insert(class_field.name, (i, false));
318     }
319
320     // Typecheck each field.
321     let mut found_fields = HashSet::new();
322     for field in fields.iter() {
323         match field_map.find_mut(&field.ident.name) {
324             Some(&(_, true)) => {
325                 tcx.sess.span_err(span,
326                     format!("field `{}` bound twice in pattern",
327                             token::get_ident(field.ident)).as_slice());
328             }
329             Some(&(index, ref mut used)) => {
330                 *used = true;
331                 let class_field = *class_fields.get(index);
332                 let field_type = ty::lookup_field_type(tcx,
333                                                        class_id,
334                                                        class_field.id,
335                                                        substitutions);
336                 check_pat(pcx, field.pat, field_type);
337                 found_fields.insert(index);
338             }
339             None => {
340                 let name = pprust::path_to_str(path);
341                 // Check the pattern anyway, so that attempts to look
342                 // up its type won't fail
343                 check_pat(pcx, field.pat, ty::mk_err());
344                 tcx.sess.span_err(span,
345                     format!("struct `{}` does not have a field named `{}`",
346                             name,
347                             token::get_ident(field.ident)).as_slice());
348             }
349         }
350     }
351
352     // Report an error if not all the fields were specified.
353     if !etc {
354         for (i, field) in class_fields.iter().enumerate() {
355             if found_fields.contains(&i) {
356                 continue;
357             }
358
359             tcx.sess
360                .span_err(span,
361                          format!("pattern does not mention field `{}`",
362                                  token::get_name(field.name)).as_slice());
363         }
364     }
365 }
366
367 pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: Span,
368                         expected: ty::t, path: &ast::Path,
369                         fields: &[ast::FieldPat], etc: bool,
370                         struct_id: ast::DefId,
371                         substitutions: &ty::substs) {
372     let fcx = pcx.fcx;
373     let tcx = pcx.fcx.ccx.tcx;
374
375     let class_fields = ty::lookup_struct_fields(tcx, struct_id);
376
377     // Check to ensure that the struct is the one specified.
378     match tcx.def_map.borrow().find(&pat_id) {
379         Some(&ast::DefStruct(supplied_def_id))
380                 if supplied_def_id == struct_id => {
381             // OK.
382         }
383         Some(&ast::DefStruct(..)) | Some(&ast::DefVariant(..)) => {
384             let name = pprust::path_to_str(path);
385             tcx.sess
386                .span_err(span,
387                          format!("mismatched types: expected `{}` but found \
388                                   `{}`",
389                                  fcx.infcx().ty_to_str(expected),
390                                  name).as_slice());
391         }
392         _ => {
393             tcx.sess.span_bug(span, "resolve didn't write in struct ID");
394         }
395     }
396
397     check_struct_pat_fields(pcx, span, path, fields, class_fields, struct_id,
398                             substitutions, etc);
399 }
400
401 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
402                                           pat_id: ast::NodeId,
403                                           span: Span,
404                                           expected: ty::t,
405                                           path: &ast::Path,
406                                           fields: &[ast::FieldPat],
407                                           etc: bool,
408                                           enum_id: ast::DefId,
409                                           substitutions: &ty::substs) {
410     let fcx = pcx.fcx;
411     let tcx = pcx.fcx.ccx.tcx;
412
413     // Find the variant that was specified.
414     match tcx.def_map.borrow().find(&pat_id) {
415         Some(&ast::DefVariant(found_enum_id, variant_id, _))
416                 if found_enum_id == enum_id => {
417             // Get the struct fields from this struct-like enum variant.
418             let class_fields = ty::lookup_struct_fields(tcx, variant_id);
419
420             check_struct_pat_fields(pcx, span, path, fields, class_fields,
421                                     variant_id, substitutions, etc);
422         }
423         Some(&ast::DefStruct(..)) | Some(&ast::DefVariant(..)) => {
424             let name = pprust::path_to_str(path);
425             tcx.sess.span_err(span,
426                               format!("mismatched types: expected `{}` but \
427                                        found `{}`",
428                                       fcx.infcx().ty_to_str(expected),
429                                       name).as_slice());
430         }
431         _ => {
432             tcx.sess.span_bug(span, "resolve didn't write in variant");
433         }
434     }
435 }
436
437 // Pattern checking is top-down rather than bottom-up so that bindings get
438 // their types immediately.
439 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
440     let fcx = pcx.fcx;
441     let tcx = pcx.fcx.ccx.tcx;
442
443     match pat.node {
444       ast::PatWild | ast::PatWildMulti => {
445         fcx.write_ty(pat.id, expected);
446       }
447       ast::PatLit(lt) => {
448         check_expr_has_type(fcx, lt, expected);
449         fcx.write_ty(pat.id, fcx.expr_ty(lt));
450       }
451       ast::PatRange(begin, end) => {
452         check_expr_has_type(fcx, begin, expected);
453         check_expr_has_type(fcx, end, expected);
454         let b_ty =
455             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(begin));
456         let e_ty =
457             fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(end));
458         debug!("pat_range beginning type: {:?}", b_ty);
459         debug!("pat_range ending type: {:?}", e_ty);
460         if !require_same_types(
461             tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
462             || "mismatched types in range".to_string())
463         {
464             // no-op
465         } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
466             tcx.sess.span_err(pat.span, "non-numeric type used in range");
467         } else {
468             match valid_range_bounds(fcx.ccx, begin, end) {
469                 Some(false) => {
470                     tcx.sess.span_err(begin.span,
471                         "lower range bound must be less than upper");
472                 },
473                 None => {
474                     tcx.sess.span_err(begin.span,
475                         "mismatched types in range");
476                 },
477                 _ => { },
478             }
479         }
480         fcx.write_ty(pat.id, b_ty);
481       }
482       ast::PatEnum(..) |
483       ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
484         let const_did = ast_util::def_id_of_def(tcx.def_map.borrow()
485                                                    .get_copy(&pat.id));
486         let const_tpt = ty::lookup_item_type(tcx, const_did);
487         demand::suptype(fcx, pat.span, expected, const_tpt.ty);
488         fcx.write_ty(pat.id, const_tpt.ty);
489       }
490       ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
491         let typ = fcx.local_ty(pat.span, pat.id);
492
493         match bm {
494           ast::BindByRef(mutbl) => {
495             // if the binding is like
496             //    ref x | ref const x | ref mut x
497             // then the type of x is &M T where M is the mutability
498             // and T is the expected type
499             let region_var =
500                 fcx.infcx().next_region_var(
501                     infer::PatternRegion(pat.span));
502             let mt = ty::mt {ty: expected, mutbl: mutbl};
503             let region_ty = ty::mk_rptr(tcx, region_var, mt);
504             demand::eqtype(fcx, pat.span, region_ty, typ);
505           }
506           // otherwise the type of x is the expected type T
507           ast::BindByValue(_) => {
508             demand::eqtype(fcx, pat.span, expected, typ);
509           }
510         }
511
512         let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
513         if canon_id != pat.id {
514             let ct = fcx.local_ty(pat.span, canon_id);
515             demand::eqtype(fcx, pat.span, ct, typ);
516         }
517         fcx.write_ty(pat.id, typ);
518
519         debug!("(checking match) writing type for pat id {}", pat.id);
520
521         match sub {
522           Some(p) => check_pat(pcx, p, expected),
523           _ => ()
524         }
525       }
526       ast::PatIdent(_, ref path, _) => {
527         check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
528       }
529       ast::PatEnum(ref path, ref subpats) => {
530         check_pat_variant(pcx, pat, path, subpats, expected);
531       }
532       ast::PatStruct(ref path, ref fields, etc) => {
533         // Grab the class data that we care about.
534         let structure = structure_of(fcx, pat.span, expected);
535         let mut error_happened = false;
536         match *structure {
537             ty::ty_struct(cid, ref substs) => {
538                 check_struct_pat(pcx, pat.id, pat.span, expected, path,
539                                  fields.as_slice(), etc, cid, substs);
540             }
541             ty::ty_enum(eid, ref substs) => {
542                 check_struct_like_enum_variant_pat(pcx,
543                                                    pat.id,
544                                                    pat.span,
545                                                    expected,
546                                                    path,
547                                                    fields.as_slice(),
548                                                    etc,
549                                                    eid,
550                                                    substs);
551             }
552             _ => {
553                // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
554                 fcx.infcx().type_error_message_str_with_expected(pat.span,
555                                                                 |expected, actual| {
556                             expected.map_or("".to_string(),
557                                             |e| {
558                                 format_strbuf!("mismatched types: expected \
559                                                 `{}` but found {}",
560                                                e,
561                                                actual)
562                             })},
563                             Some(expected),
564                             "a structure pattern".to_string(),
565                             None);
566                 match tcx.def_map.borrow().find(&pat.id) {
567                     Some(&ast::DefStruct(supplied_def_id)) => {
568                          check_struct_pat(pcx,
569                                           pat.id,
570                                           pat.span,
571                                           ty::mk_err(),
572                                           path,
573                                           fields.as_slice(),
574                                           etc,
575                                           supplied_def_id,
576                                           &ty::substs {
577                                               self_ty: None,
578                                               tps: Vec::new(),
579                                               regions: ty::ErasedRegions,
580                                           });
581                     }
582                     _ => () // Error, but we're already in an error case
583                 }
584                 error_happened = true;
585             }
586         }
587
588         // Finally, write in the type.
589         if error_happened {
590             fcx.write_error(pat.id);
591         } else {
592             fcx.write_ty(pat.id, expected);
593         }
594       }
595       ast::PatTup(ref elts) => {
596         let s = structure_of(fcx, pat.span, expected);
597         let e_count = elts.len();
598         match *s {
599             ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
600                 for (i, elt) in elts.iter().enumerate() {
601                     check_pat(pcx, *elt, *ex_elts.get(i));
602                 }
603                 fcx.write_ty(pat.id, expected);
604             }
605             _ => {
606                 for elt in elts.iter() {
607                     check_pat(pcx, *elt, ty::mk_err());
608                 }
609                 // use terr_tuple_size if both types are tuples
610                 let type_error = match *s {
611                     ty::ty_tup(ref ex_elts) => {
612                         ty::terr_tuple_size(ty::expected_found {
613                             expected: ex_elts.len(),
614                             found: e_count
615                         })
616                     }
617                     _ => ty::terr_mismatch
618                 };
619                 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
620                 fcx.infcx().type_error_message_str_with_expected(pat.span,
621                                                                  |expected,
622                                                                   actual| {
623                         expected.map_or("".to_string(), |e| {
624                             format_strbuf!("mismatched types: expected `{}` \
625                                             but found {}",
626                                            e,
627                                            actual)
628                         }
629                     )},
630                     Some(expected),
631                     "tuple".to_string(),
632                     Some(&type_error));
633                 fcx.write_error(pat.id);
634             }
635         }
636       }
637       ast::PatUniq(inner) => {
638           check_pointer_pat(pcx, Send, inner, pat.id, pat.span, expected);
639       }
640       ast::PatRegion(inner) => {
641           check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected);
642       }
643       ast::PatVec(ref before, slice, ref after) => {
644         let default_region_var =
645             fcx.infcx().next_region_var(
646                 infer::PatternRegion(pat.span));
647
648         let check_err = || {
649             for &elt in before.iter() {
650                 check_pat(pcx, elt, ty::mk_err());
651             }
652             for &elt in slice.iter() {
653                 check_pat(pcx, elt, ty::mk_err());
654             }
655             for &elt in after.iter() {
656                 check_pat(pcx, elt, ty::mk_err());
657             }
658             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
659             fcx.infcx().type_error_message_str_with_expected(
660                 pat.span,
661                 |expected, actual| {
662                     expected.map_or("".to_string(),
663                                     |e| {
664                         format_strbuf!("mismatched types: expected `{}` but \
665                                         found {}",
666                                        e,
667                                        actual)
668                     })
669                 },
670                 Some(expected),
671                 "a vector pattern".to_string(),
672                 None);
673             fcx.write_error(pat.id);
674         };
675
676         let (elt_type, region_var, mutbl) = match *structure_of(fcx,
677                                                                 pat.span,
678                                                                 expected) {
679           ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable),
680           ty::ty_uniq(t) => match ty::get(t).sty {
681               ty::ty_vec(mt, None) => {
682                   fcx.type_error_message(pat.span,
683                                          |_| {
684                                             "unique vector patterns are no \
685                                              longer supported".to_string()
686                                          },
687                                          expected,
688                                          None);
689                   (mt.ty, default_region_var, ast::MutImmutable)
690               }
691               _ => {
692                   check_err();
693                   return;
694               }
695           },
696           ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
697               ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl),
698               _ => {
699                   check_err();
700                   return;
701               }
702           },
703           _ => {
704               check_err();
705               return;
706           }
707         };
708         for elt in before.iter() {
709             check_pat(pcx, *elt, elt_type);
710         }
711         match slice {
712             Some(slice_pat) => {
713                 let slice_ty = ty::mk_slice(tcx,
714                                             region_var,
715                                             ty::mt {ty: elt_type, mutbl: mutbl});
716                 check_pat(pcx, slice_pat, slice_ty);
717             }
718             None => ()
719         }
720         for elt in after.iter() {
721             check_pat(pcx, *elt, elt_type);
722         }
723         fcx.write_ty(pat.id, expected);
724       }
725     }
726 }
727
728 // Helper function to check @, box and & patterns
729 pub fn check_pointer_pat(pcx: &pat_ctxt,
730                          pointer_kind: PointerKind,
731                          inner: &ast::Pat,
732                          pat_id: ast::NodeId,
733                          span: Span,
734                          expected: ty::t) {
735     let fcx = pcx.fcx;
736     let check_inner: |ty::t| = |e_inner| {
737         check_pat(pcx, inner, e_inner);
738         fcx.write_ty(pat_id, expected);
739     };
740     match *structure_of(fcx, span, expected) {
741         ty::ty_uniq(e_inner) if pointer_kind == Send => {
742             check_inner(e_inner);
743         }
744         ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
745             check_inner(e_inner.ty);
746         }
747         _ => {
748             check_pat(pcx, inner, ty::mk_err());
749             // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
750             fcx.infcx().type_error_message_str_with_expected(
751                 span,
752                 |expected, actual| {
753                     expected.map_or("".to_string(), |e| {
754                         format_strbuf!("mismatched types: expected `{}` but \
755                                         found {}",
756                                        e,
757                                        actual)
758                     })
759                 },
760                 Some(expected),
761                 format_strbuf!("{} pattern", match pointer_kind {
762                     Send => "a box",
763                     Borrowed => "an `&`-pointer",
764                 }),
765                 None);
766             fcx.write_error(pat_id);
767           }
768     }
769 }
770
771 #[deriving(Eq)]
772 pub enum PointerKind {
773     Send,
774     Borrowed,
775 }
776