]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/_match.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[rust.git] / src / librustc_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 use middle::const_eval;
12 use middle::def;
13 use middle::infer;
14 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
15 use middle::subst::{Substs};
16 use middle::ty::{self, Ty};
17 use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
18 use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
19 use check::{instantiate_path, structurally_resolved_type};
20 use require_same_types;
21 use util::nodemap::FnvHashMap;
22 use util::ppaux::Repr;
23
24 use std::cmp::{self, Ordering};
25 use std::collections::hash_map::Entry::{Occupied, Vacant};
26 use syntax::ast;
27 use syntax::ast_util;
28 use syntax::codemap::{Span, Spanned};
29 use syntax::parse::token;
30 use syntax::print::pprust;
31 use syntax::ptr::P;
32
33 pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
34                            pat: &'tcx ast::Pat,
35                            expected: Ty<'tcx>)
36 {
37     let fcx = pcx.fcx;
38     let tcx = pcx.fcx.ccx.tcx;
39
40     debug!("check_pat(pat={},expected={})",
41            pat.repr(tcx),
42            expected.repr(tcx));
43
44     match pat.node {
45         ast::PatWild(_) => {
46             fcx.write_ty(pat.id, expected);
47         }
48         ast::PatLit(ref lt) => {
49             check_expr(fcx, &**lt);
50             let expr_ty = fcx.expr_ty(&**lt);
51             fcx.write_ty(pat.id, expr_ty);
52
53             // somewhat surprising: in this case, the subtyping
54             // relation goes the opposite way as the other
55             // cases. Actually what we really want is not a subtyping
56             // relation at all but rather that there exists a LUB (so
57             // that they can be compared). However, in practice,
58             // constants are always scalars or strings.  For scalars
59             // subtyping is irrelevant, and for strings `expr_ty` is
60             // type is `&'static str`, so if we say that
61             //
62             //     &'static str <: expected
63             //
64             // that's equivalent to there existing a LUB.
65             demand::suptype(fcx, pat.span, expected, expr_ty);
66         }
67         ast::PatRange(ref begin, ref end) => {
68             check_expr(fcx, &**begin);
69             check_expr(fcx, &**end);
70
71             let lhs_ty = fcx.expr_ty(&**begin);
72             let rhs_ty = fcx.expr_ty(&**end);
73
74             let lhs_eq_rhs =
75                 require_same_types(
76                     tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty,
77                     || "mismatched types in range".to_string());
78
79             let numeric_or_char =
80                 lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty));
81
82             if numeric_or_char {
83                 match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty)) {
84                     Some(Ordering::Less) |
85                     Some(Ordering::Equal) => {}
86                     Some(Ordering::Greater) => {
87                         span_err!(tcx.sess, begin.span, E0030,
88                             "lower range bound must be less than upper");
89                     }
90                     None => {
91                         span_err!(tcx.sess, begin.span, E0031,
92                             "mismatched types in range");
93                     }
94                 }
95             } else {
96                 span_err!(tcx.sess, begin.span, E0029,
97                           "only char and numeric types are allowed in range");
98             }
99
100             fcx.write_ty(pat.id, lhs_ty);
101
102             // subtyping doesn't matter here, as the value is some kind of scalar
103             demand::eqtype(fcx, pat.span, expected, lhs_ty);
104         }
105         ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
106             let const_did = tcx.def_map.borrow()[pat.id].clone().def_id();
107             let const_scheme = ty::lookup_item_type(tcx, const_did);
108             assert!(const_scheme.generics.is_empty());
109             let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
110                                                            &Substs::empty(),
111                                                            &const_scheme.ty);
112             fcx.write_ty(pat.id, const_ty);
113
114             // FIXME(#20489) -- we should limit the types here to scalars or something!
115
116             // As with PatLit, what we really want here is that there
117             // exist a LUB, but for the cases that can occur, subtype
118             // is good enough.
119             demand::suptype(fcx, pat.span, expected, const_ty);
120         }
121         ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
122             let typ = fcx.local_ty(pat.span, pat.id);
123             match bm {
124                 ast::BindByRef(mutbl) => {
125                     // if the binding is like
126                     //    ref x | ref const x | ref mut x
127                     // then `x` is assigned a value of type `&M T` where M is the mutability
128                     // and T is the expected type.
129                     let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
130                     let mt = ty::mt { ty: expected, mutbl: mutbl };
131                     let region_ty = ty::mk_rptr(tcx, tcx.mk_region(region_var), mt);
132
133                     // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
134                     // required. However, we use equality, which is stronger. See (*) for
135                     // an explanation.
136                     demand::eqtype(fcx, pat.span, region_ty, typ);
137                 }
138                 // otherwise the type of x is the expected type T
139                 ast::BindByValue(_) => {
140                     // As above, `T <: typeof(x)` is required but we
141                     // use equality, see (*) below.
142                     demand::eqtype(fcx, pat.span, expected, typ);
143                 }
144             }
145
146             fcx.write_ty(pat.id, typ);
147
148             // if there are multiple arms, make sure they all agree on
149             // what the type of the binding `x` ought to be
150             let canon_id = pcx.map[path.node];
151             if canon_id != pat.id {
152                 let ct = fcx.local_ty(pat.span, canon_id);
153                 demand::eqtype(fcx, pat.span, ct, typ);
154             }
155
156             if let Some(ref p) = *sub {
157                 check_pat(pcx, &**p, expected);
158             }
159         }
160         ast::PatIdent(_, ref path, _) => {
161             let path = ast_util::ident_to_path(path.span, path.node);
162             check_pat_enum(pcx, pat, &path, Some(&[]), expected);
163         }
164         ast::PatEnum(ref path, ref subpats) => {
165             let subpats = subpats.as_ref().map(|v| &v[..]);
166             check_pat_enum(pcx, pat, path, subpats, expected);
167         }
168         ast::PatStruct(ref path, ref fields, etc) => {
169             check_pat_struct(pcx, pat, path, fields, etc, expected);
170         }
171         ast::PatTup(ref elements) => {
172             let element_tys: Vec<_> =
173                 (0..elements.len()).map(|_| fcx.infcx().next_ty_var())
174                                         .collect();
175             let pat_ty = ty::mk_tup(tcx, element_tys.clone());
176             fcx.write_ty(pat.id, pat_ty);
177             demand::eqtype(fcx, pat.span, expected, pat_ty);
178             for (element_pat, element_ty) in elements.iter().zip(element_tys.into_iter()) {
179                 check_pat(pcx, &**element_pat, element_ty);
180             }
181         }
182         ast::PatBox(ref inner) => {
183             let inner_ty = fcx.infcx().next_ty_var();
184             let uniq_ty = ty::mk_uniq(tcx, inner_ty);
185
186             if check_dereferencable(pcx, pat.span, expected, &**inner) {
187                 // Here, `demand::subtype` is good enough, but I don't
188                 // think any errors can be introduced by using
189                 // `demand::eqtype`.
190                 demand::eqtype(fcx, pat.span, expected, uniq_ty);
191                 fcx.write_ty(pat.id, uniq_ty);
192                 check_pat(pcx, &**inner, inner_ty);
193             } else {
194                 fcx.write_error(pat.id);
195                 check_pat(pcx, &**inner, tcx.types.err);
196             }
197         }
198         ast::PatRegion(ref inner, mutbl) => {
199             let inner_ty = fcx.infcx().next_ty_var();
200
201             let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
202             let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
203             let rptr_ty = ty::mk_rptr(tcx, tcx.mk_region(region), mt);
204
205             if check_dereferencable(pcx, pat.span, expected, &**inner) {
206                 // `demand::subtype` would be good enough, but using
207                 // `eqtype` turns out to be equally general. See (*)
208                 // below for details.
209                 demand::eqtype(fcx, pat.span, expected, rptr_ty);
210                 fcx.write_ty(pat.id, rptr_ty);
211                 check_pat(pcx, &**inner, inner_ty);
212             } else {
213                 fcx.write_error(pat.id);
214                 check_pat(pcx, &**inner, tcx.types.err);
215             }
216         }
217         ast::PatVec(ref before, ref slice, ref after) => {
218             let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
219             let inner_ty = fcx.infcx().next_ty_var();
220             let pat_ty = match expected_ty.sty {
221                 ty::ty_vec(_, Some(size)) => ty::mk_vec(tcx, inner_ty, Some({
222                     let min_len = before.len() + after.len();
223                     match *slice {
224                         Some(_) => cmp::max(min_len, size),
225                         None => min_len
226                     }
227                 })),
228                 _ => {
229                     let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
230                     ty::mk_slice(tcx, tcx.mk_region(region), ty::mt {
231                         ty: inner_ty,
232                         mutbl: ty::deref(expected_ty, true).map(|mt| mt.mutbl)
233                                                            .unwrap_or(ast::MutImmutable)
234                     })
235                 }
236             };
237
238             fcx.write_ty(pat.id, pat_ty);
239
240             // `demand::subtype` would be good enough, but using
241             // `eqtype` turns out to be equally general. See (*)
242             // below for details.
243             demand::eqtype(fcx, pat.span, expected, pat_ty);
244
245             for elt in before {
246                 check_pat(pcx, &**elt, inner_ty);
247             }
248             if let Some(ref slice) = *slice {
249                 let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
250                 let mutbl = ty::deref(expected_ty, true)
251                     .map_or(ast::MutImmutable, |mt| mt.mutbl);
252
253                 let slice_ty = ty::mk_slice(tcx, tcx.mk_region(region), ty::mt {
254                     ty: inner_ty,
255                     mutbl: mutbl
256                 });
257                 check_pat(pcx, &**slice, slice_ty);
258             }
259             for elt in after {
260                 check_pat(pcx, &**elt, inner_ty);
261             }
262         }
263         ast::PatMac(_) => tcx.sess.bug("unexpanded macro")
264     }
265
266
267     // (*) In most of the cases above (literals and constants being
268     // the exception), we relate types using strict equality, evewn
269     // though subtyping would be sufficient. There are a few reasons
270     // for this, some of which are fairly subtle and which cost me
271     // (nmatsakis) an hour or two debugging to remember, so I thought
272     // I'd write them down this time.
273     //
274     // 1. Most importantly, there is no loss of expressiveness
275     // here. What we are saying is that the type of `x`
276     // becomes *exactly* what is expected. This might seem
277     // like it will cause errors in a case like this:
278     //
279     // ```
280     // fn foo<'x>(x: &'x int) {
281     //    let a = 1;
282     //    let mut z = x;
283     //    z = &a;
284     // }
285     // ```
286     //
287     // The reason we might get an error is that `z` might be
288     // assigned a type like `&'x int`, and then we would have
289     // a problem when we try to assign `&a` to `z`, because
290     // the lifetime of `&a` (i.e., the enclosing block) is
291     // shorter than `'x`.
292     //
293     // HOWEVER, this code works fine. The reason is that the
294     // expected type here is whatever type the user wrote, not
295     // the initializer's type. In this case the user wrote
296     // nothing, so we are going to create a type variable `Z`.
297     // Then we will assign the type of the initializer (`&'x
298     // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
299     // will instantiate `Z` as a type `&'0 int` where `'0` is
300     // a fresh region variable, with the constraint that `'x :
301     // '0`.  So basically we're all set.
302     //
303     // Note that there are two tests to check that this remains true
304     // (`regions-reassign-{match,let}-bound-pointer.rs`).
305     //
306     // 2. Things go horribly wrong if we use subtype. The reason for
307     // THIS is a fairly subtle case involving bound regions. See the
308     // `givens` field in `region_inference`, as well as the test
309     // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
310     // for details. Short version is that we must sometimes detect
311     // relationships between specific region variables and regions
312     // bound in a closure signature, and that detection gets thrown
313     // off when we substitute fresh region variables here to enable
314     // subtyping.
315 }
316
317 pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
318                                       span: Span, expected: Ty<'tcx>,
319                                       inner: &ast::Pat) -> bool {
320     let fcx = pcx.fcx;
321     let tcx = pcx.fcx.ccx.tcx;
322     if pat_is_binding(&tcx.def_map, inner) {
323         let expected = fcx.infcx().shallow_resolve(expected);
324         ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty {
325             ty::ty_trait(_) => {
326                 // This is "x = SomeTrait" being reduced from
327                 // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
328                 span_err!(tcx.sess, span, E0033,
329                           "type `{}` cannot be dereferenced",
330                           fcx.infcx().ty_to_string(expected));
331                 false
332             }
333             _ => true
334         })
335     } else {
336         true
337     }
338 }
339
340 pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
341                              expr: &'tcx ast::Expr,
342                              discrim: &'tcx ast::Expr,
343                              arms: &'tcx [ast::Arm],
344                              expected: Expectation<'tcx>,
345                              match_src: ast::MatchSource) {
346     let tcx = fcx.ccx.tcx;
347
348     let discrim_ty = fcx.infcx().next_ty_var();
349     check_expr_has_type(fcx, discrim, discrim_ty);
350
351     // Typecheck the patterns first, so that we get types for all the
352     // bindings.
353     for arm in arms {
354         let mut pcx = pat_ctxt {
355             fcx: fcx,
356             map: pat_id_map(&tcx.def_map, &*arm.pats[0]),
357         };
358         for p in &arm.pats {
359             check_pat(&mut pcx, &**p, discrim_ty);
360         }
361     }
362
363     // Now typecheck the blocks.
364     //
365     // The result of the match is the common supertype of all the
366     // arms. Start out the value as bottom, since it's the, well,
367     // bottom the type lattice, and we'll be moving up the lattice as
368     // we process each arm. (Note that any match with 0 arms is matching
369     // on any empty type and is therefore unreachable; should the flow
370     // of execution reach it, we will panic, so bottom is an appropriate
371     // type in that case)
372     let expected = expected.adjust_for_branches(fcx);
373     let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| {
374         let bty = match expected {
375             // We don't coerce to `()` so that if the match expression is a
376             // statement it's branches can have any consistent type. That allows
377             // us to give better error messages (pointing to a usually better
378             // arm for inconsistent arms or to the whole match when a `()` type
379             // is required).
380             Expectation::ExpectHasType(ety) if ety != ty::mk_nil(fcx.tcx()) => {
381                 check_expr_coercable_to_type(fcx, &*arm.body, ety);
382                 ety
383             }
384             _ => {
385                 check_expr_with_expectation(fcx, &*arm.body, expected);
386                 fcx.node_ty(arm.body.id)
387             }
388         };
389
390         if let Some(ref e) = arm.guard {
391             check_expr_has_type(fcx, &**e, tcx.types.bool);
392         }
393
394         if ty::type_is_error(result_ty) || ty::type_is_error(bty) {
395             tcx.types.err
396         } else {
397             let (origin, expected, found) = match match_src {
398                 /* if-let construct without an else block */
399                 ast::MatchSource::IfLetDesugar { contains_else_clause }
400                 if !contains_else_clause => (
401                     infer::IfExpressionWithNoElse(expr.span),
402                     bty,
403                     result_ty,
404                 ),
405                 _ => (
406                     infer::MatchExpressionArm(expr.span, arm.body.span),
407                     result_ty,
408                     bty,
409                 ),
410             };
411
412             infer::common_supertype(
413                 fcx.infcx(),
414                 origin,
415                 true,
416                 expected,
417                 found,
418             )
419         }
420     });
421
422     fcx.write_ty(expr.id, result_ty);
423 }
424
425 pub struct pat_ctxt<'a, 'tcx: 'a> {
426     pub fcx: &'a FnCtxt<'a, 'tcx>,
427     pub map: PatIdMap,
428 }
429
430 pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
431                                   path: &ast::Path, fields: &'tcx [Spanned<ast::FieldPat>],
432                                   etc: bool, expected: Ty<'tcx>) {
433     let fcx = pcx.fcx;
434     let tcx = pcx.fcx.ccx.tcx;
435
436     let def = tcx.def_map.borrow()[pat.id].clone();
437     let (enum_def_id, variant_def_id) = match def {
438         def::DefTrait(_) => {
439             let name = pprust::path_to_string(path);
440             span_err!(tcx.sess, pat.span, E0168,
441                 "use of trait `{}` in a struct pattern", name);
442             fcx.write_error(pat.id);
443
444             for field in fields {
445                 check_pat(pcx, &*field.node.pat, tcx.types.err);
446             }
447             return;
448         },
449         _ => {
450             let def_type = ty::lookup_item_type(tcx, def.def_id());
451             match def_type.ty.sty {
452                 ty::ty_struct(struct_def_id, _) =>
453                     (struct_def_id, struct_def_id),
454                 ty::ty_enum(enum_def_id, _)
455                     if def == def::DefVariant(enum_def_id, def.def_id(), true) =>
456                     (enum_def_id, def.def_id()),
457                 _ => {
458                     let name = pprust::path_to_string(path);
459                     span_err!(tcx.sess, pat.span, E0163,
460                         "`{}` does not name a struct or a struct variant", name);
461                     fcx.write_error(pat.id);
462
463                     for field in fields {
464                         check_pat(pcx, &*field.node.pat, tcx.types.err);
465                     }
466                     return;
467                 }
468             }
469         }
470     };
471
472     instantiate_path(pcx.fcx,
473                      path,
474                      ty::lookup_item_type(tcx, enum_def_id),
475                      &ty::lookup_predicates(tcx, enum_def_id),
476                      None,
477                      def,
478                      pat.span,
479                      pat.id);
480
481     let pat_ty = fcx.node_ty(pat.id);
482     demand::eqtype(fcx, pat.span, expected, pat_ty);
483
484     let item_substs = fcx
485         .item_substs()
486         .get(&pat.id)
487         .map(|substs| substs.substs.clone())
488         .unwrap_or_else(|| Substs::empty());
489
490     let struct_fields = ty::struct_fields(tcx, variant_def_id, &item_substs);
491     check_struct_pat_fields(pcx, pat.span, fields, &struct_fields,
492                             variant_def_id, etc);
493 }
494
495 pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
496                                 pat: &ast::Pat,
497                                 path: &ast::Path,
498                                 subpats: Option<&'tcx [P<ast::Pat>]>,
499                                 expected: Ty<'tcx>)
500 {
501     // Typecheck the path.
502     let fcx = pcx.fcx;
503     let tcx = pcx.fcx.ccx.tcx;
504
505     let def = tcx.def_map.borrow()[pat.id].clone();
506     let enum_def = def.variant_def_ids()
507         .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
508
509     let ctor_scheme = ty::lookup_item_type(tcx, enum_def);
510     let ctor_predicates = ty::lookup_predicates(tcx, enum_def);
511     let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) {
512         let fn_ret = ty::no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty)).unwrap();
513         ty::TypeScheme {
514             ty: fn_ret.unwrap(),
515             generics: ctor_scheme.generics,
516         }
517     } else {
518         ctor_scheme
519     };
520     instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id);
521
522     let pat_ty = fcx.node_ty(pat.id);
523     demand::eqtype(fcx, pat.span, expected, pat_ty);
524
525     let real_path_ty = fcx.node_ty(pat.id);
526     let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
527         ty::ty_enum(enum_def_id, expected_substs)
528             if def == def::DefVariant(enum_def_id, def.def_id(), false) =>
529         {
530             let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id());
531             (variant.args.iter()
532                          .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t))
533                          .collect(),
534              "variant")
535         }
536         ty::ty_struct(struct_def_id, expected_substs) => {
537             let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs);
538             (struct_fields.iter()
539                           .map(|field| fcx.instantiate_type_scheme(pat.span,
540                                                                    expected_substs,
541                                                                    &field.mt.ty))
542                           .collect(),
543              "struct")
544         }
545         _ => {
546             let name = pprust::path_to_string(path);
547             span_err!(tcx.sess, pat.span, E0164,
548                 "`{}` does not name a non-struct variant or a tuple struct", name);
549             fcx.write_error(pat.id);
550
551             if let Some(subpats) = subpats {
552                 for pat in subpats {
553                     check_pat(pcx, &**pat, tcx.types.err);
554                 }
555             }
556             return;
557         }
558     };
559
560     if let Some(subpats) = subpats {
561         if subpats.len() == arg_tys.len() {
562             for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) {
563                 check_pat(pcx, &**subpat, *arg_ty);
564             }
565         } else if arg_tys.len() == 0 {
566             span_err!(tcx.sess, pat.span, E0024,
567                       "this pattern has {} field{}, but the corresponding {} has no fields",
568                       subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
569
570             for pat in subpats {
571                 check_pat(pcx, &**pat, tcx.types.err);
572             }
573         } else {
574             span_err!(tcx.sess, pat.span, E0023,
575                       "this pattern has {} field{}, but the corresponding {} has {} field{}",
576                       subpats.len(), if subpats.len() == 1 {""} else {"s"},
577                       kind_name,
578                       arg_tys.len(), if arg_tys.len() == 1 {""} else {"s"});
579
580             for pat in subpats {
581                 check_pat(pcx, &**pat, tcx.types.err);
582             }
583         }
584     }
585 }
586
587 /// `path` is the AST path item naming the type of this struct.
588 /// `fields` is the field patterns of the struct pattern.
589 /// `struct_fields` describes the type of each field of the struct.
590 /// `struct_id` is the ID of the struct.
591 /// `etc` is true if the pattern said '...' and false otherwise.
592 pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
593                                          span: Span,
594                                          fields: &'tcx [Spanned<ast::FieldPat>],
595                                          struct_fields: &[ty::field<'tcx>],
596                                          struct_id: ast::DefId,
597                                          etc: bool) {
598     let tcx = pcx.fcx.ccx.tcx;
599
600     // Index the struct fields' types.
601     let field_type_map = struct_fields
602         .iter()
603         .map(|field| (field.name, field.mt.ty))
604         .collect::<FnvHashMap<_, _>>();
605
606     // Keep track of which fields have already appeared in the pattern.
607     let mut used_fields = FnvHashMap();
608
609     // Typecheck each field.
610     for &Spanned { node: ref field, span } in fields {
611         let field_type = match used_fields.entry(field.ident.name) {
612             Occupied(occupied) => {
613                 span_err!(tcx.sess, span, E0025,
614                     "field `{}` bound multiple times in the pattern",
615                     token::get_ident(field.ident));
616                 span_note!(tcx.sess, *occupied.get(),
617                     "field `{}` previously bound here",
618                     token::get_ident(field.ident));
619                 tcx.types.err
620             }
621             Vacant(vacant) => {
622                 vacant.insert(span);
623                 field_type_map.get(&field.ident.name).cloned()
624                     .unwrap_or_else(|| {
625                         span_err!(tcx.sess, span, E0026,
626                             "struct `{}` does not have a field named `{}`",
627                             ty::item_path_str(tcx, struct_id),
628                             token::get_ident(field.ident));
629                         tcx.types.err
630                     })
631             }
632         };
633
634         let field_type = pcx.fcx.normalize_associated_types_in(span, &field_type);
635
636         check_pat(pcx, &*field.pat, field_type);
637     }
638
639     // Report an error if not all the fields were specified.
640     if !etc {
641         for field in struct_fields
642             .iter()
643             .filter(|field| !used_fields.contains_key(&field.name)) {
644             span_err!(tcx.sess, span, E0027,
645                 "pattern does not mention field `{}`",
646                 token::get_name(field.name));
647         }
648     }
649 }