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