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