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