]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/_match.rs
remove `get_ident` and `get_name`, make `as_str` sound
[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};
14 use middle::pat_util::pat_is_resolved_const;
15 use middle::privacy::{AllPublic, LastMod};
16 use middle::subst::Substs;
17 use middle::ty::{self, Ty, HasTypeFlags};
18 use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
19 use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
20 use check::{check_expr_with_lvalue_pref, LvaluePreference};
21 use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
22 use require_same_types;
23 use util::nodemap::FnvHashMap;
24
25 use std::cmp;
26 use std::collections::hash_map::Entry::{Occupied, Vacant};
27 use syntax::ast;
28 use syntax::ast_util;
29 use syntax::codemap::{Span, Spanned};
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,
42            expected);
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
52             // Byte string patterns behave the same way as array patterns
53             // They can denote both statically and dynamically sized byte arrays
54             let mut pat_ty = expr_ty;
55             if let ast::ExprLit(ref lt) = lt.node {
56                 if let ast::LitBinary(_) = lt.node {
57                     let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
58                     if let ty::TyRef(_, mt) = expected_ty.sty {
59                         if let ty::TySlice(_) = mt.ty.sty {
60                             pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
61                                                      tcx.mk_slice(tcx.types.u8))
62                         }
63                     }
64                 }
65             }
66
67             fcx.write_ty(pat.id, pat_ty);
68
69             // somewhat surprising: in this case, the subtyping
70             // relation goes the opposite way as the other
71             // cases. Actually what we really want is not a subtyping
72             // relation at all but rather that there exists a LUB (so
73             // that they can be compared). However, in practice,
74             // constants are always scalars or strings.  For scalars
75             // subtyping is irrelevant, and for strings `expr_ty` is
76             // type is `&'static str`, so if we say that
77             //
78             //     &'static str <: expected
79             //
80             // that's equivalent to there existing a LUB.
81             demand::suptype(fcx, pat.span, expected, pat_ty);
82         }
83         ast::PatRange(ref begin, ref end) => {
84             check_expr(fcx, begin);
85             check_expr(fcx, end);
86
87             let lhs_ty = fcx.expr_ty(begin);
88             let rhs_ty = fcx.expr_ty(end);
89
90             // Check that both end-points are of numeric or char type.
91             let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
92             let lhs_compat = numeric_or_char(lhs_ty);
93             let rhs_compat = numeric_or_char(rhs_ty);
94
95             if !lhs_compat || !rhs_compat {
96                 let span = if !lhs_compat && !rhs_compat {
97                     pat.span
98                 } else if !lhs_compat {
99                     begin.span
100                 } else {
101                     end.span
102                 };
103
104                 // Note: spacing here is intentional, we want a space before "start" and "end".
105                 span_err!(tcx.sess, span, E0029,
106                           "only char and numeric types are allowed in range patterns\n \
107                            start type: {}\n end type: {}",
108                           fcx.infcx().ty_to_string(lhs_ty),
109                           fcx.infcx().ty_to_string(rhs_ty)
110                 );
111                 return;
112             }
113
114             // Check that the types of the end-points can be unified.
115             let types_unify = require_same_types(
116                     tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty,
117                     || "mismatched types in range".to_string()
118             );
119
120             // It's ok to return without a message as `require_same_types` prints an error.
121             if !types_unify {
122                 return;
123             }
124
125             // Now that we know the types can be unified we find the unified type and use
126             // it to type the entire expression.
127             let common_type = fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
128
129             fcx.write_ty(pat.id, common_type);
130
131             // subtyping doesn't matter here, as the value is some kind of scalar
132             demand::eqtype(fcx, pat.span, expected, lhs_ty);
133         }
134         ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => {
135             let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
136             let const_scheme = tcx.lookup_item_type(const_did);
137             assert!(const_scheme.generics.is_empty());
138             let const_ty = pcx.fcx.instantiate_type_scheme(pat.span,
139                                                            &Substs::empty(),
140                                                            &const_scheme.ty);
141             fcx.write_ty(pat.id, const_ty);
142
143             // FIXME(#20489) -- we should limit the types here to scalars or something!
144
145             // As with PatLit, what we really want here is that there
146             // exist a LUB, but for the cases that can occur, subtype
147             // is good enough.
148             demand::suptype(fcx, pat.span, expected, const_ty);
149         }
150         ast::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => {
151             let typ = fcx.local_ty(pat.span, pat.id);
152             match bm {
153                 ast::BindByRef(mutbl) => {
154                     // if the binding is like
155                     //    ref x | ref const x | ref mut x
156                     // then `x` is assigned a value of type `&M T` where M is the mutability
157                     // and T is the expected type.
158                     let region_var = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
159                     let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
160                     let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
161
162                     // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
163                     // required. However, we use equality, which is stronger. See (*) for
164                     // an explanation.
165                     demand::eqtype(fcx, pat.span, region_ty, typ);
166                 }
167                 // otherwise the type of x is the expected type T
168                 ast::BindByValue(_) => {
169                     // As above, `T <: typeof(x)` is required but we
170                     // use equality, see (*) below.
171                     demand::eqtype(fcx, pat.span, expected, typ);
172                 }
173             }
174
175             fcx.write_ty(pat.id, typ);
176
177             // if there are multiple arms, make sure they all agree on
178             // what the type of the binding `x` ought to be
179             let canon_id = *pcx.map.get(&path.node).unwrap();
180             if canon_id != pat.id {
181                 let ct = fcx.local_ty(pat.span, canon_id);
182                 demand::eqtype(fcx, pat.span, ct, typ);
183             }
184
185             if let Some(ref p) = *sub {
186                 check_pat(pcx, &**p, expected);
187             }
188         }
189         ast::PatIdent(_, ref path, _) => {
190             let path = ast_util::ident_to_path(path.span, path.node);
191             check_pat_enum(pcx, pat, &path, Some(&[]), expected);
192         }
193         ast::PatEnum(ref path, ref subpats) => {
194             let subpats = subpats.as_ref().map(|v| &v[..]);
195             check_pat_enum(pcx, pat, path, subpats, expected);
196         }
197         ast::PatQPath(ref qself, ref path) => {
198             let self_ty = fcx.to_ty(&qself.ty);
199             let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
200                 d
201             } else if qself.position == 0 {
202                 def::PathResolution {
203                     // This is just a sentinel for finish_resolving_def_to_ty.
204                     base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
205                     last_private: LastMod(AllPublic),
206                     depth: path.segments.len()
207                 }
208             } else {
209                 tcx.sess.span_bug(pat.span,
210                                   &format!("unbound path {:?}", pat))
211             };
212             if let Some((opt_ty, segments, def)) =
213                     resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
214                                             path, pat.span, pat.id) {
215                 if check_assoc_item_is_const(pcx, def, pat.span) {
216                     let scheme = tcx.lookup_item_type(def.def_id());
217                     let predicates = tcx.lookup_predicates(def.def_id());
218                     instantiate_path(fcx, segments,
219                                      scheme, &predicates,
220                                      opt_ty, def, pat.span, pat.id);
221                     let const_ty = fcx.node_ty(pat.id);
222                     demand::suptype(fcx, pat.span, expected, const_ty);
223                 } else {
224                     fcx.write_error(pat.id)
225                 }
226             }
227         }
228         ast::PatStruct(ref path, ref fields, etc) => {
229             check_pat_struct(pcx, pat, path, fields, etc, expected);
230         }
231         ast::PatTup(ref elements) => {
232             let element_tys: Vec<_> =
233                 (0..elements.len()).map(|_| fcx.infcx().next_ty_var())
234                                         .collect();
235             let pat_ty = tcx.mk_tup(element_tys.clone());
236             fcx.write_ty(pat.id, pat_ty);
237             demand::eqtype(fcx, pat.span, expected, pat_ty);
238             for (element_pat, element_ty) in elements.iter().zip(element_tys) {
239                 check_pat(pcx, &**element_pat, element_ty);
240             }
241         }
242         ast::PatBox(ref inner) => {
243             let inner_ty = fcx.infcx().next_ty_var();
244             let uniq_ty = tcx.mk_box(inner_ty);
245
246             if check_dereferencable(pcx, pat.span, expected, &**inner) {
247                 // Here, `demand::subtype` is good enough, but I don't
248                 // think any errors can be introduced by using
249                 // `demand::eqtype`.
250                 demand::eqtype(fcx, pat.span, expected, uniq_ty);
251                 fcx.write_ty(pat.id, uniq_ty);
252                 check_pat(pcx, &**inner, inner_ty);
253             } else {
254                 fcx.write_error(pat.id);
255                 check_pat(pcx, &**inner, tcx.types.err);
256             }
257         }
258         ast::PatRegion(ref inner, mutbl) => {
259             let inner_ty = fcx.infcx().next_ty_var();
260
261             let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
262             let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
263             let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
264
265             if check_dereferencable(pcx, pat.span, expected, &**inner) {
266                 // `demand::subtype` would be good enough, but using
267                 // `eqtype` turns out to be equally general. See (*)
268                 // below for details.
269                 demand::eqtype(fcx, pat.span, expected, rptr_ty);
270                 fcx.write_ty(pat.id, rptr_ty);
271                 check_pat(pcx, &**inner, inner_ty);
272             } else {
273                 fcx.write_error(pat.id);
274                 check_pat(pcx, &**inner, tcx.types.err);
275             }
276         }
277         ast::PatVec(ref before, ref slice, ref after) => {
278             let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
279             let inner_ty = fcx.infcx().next_ty_var();
280             let pat_ty = match expected_ty.sty {
281                 ty::TyArray(_, size) => tcx.mk_array(inner_ty, {
282                     let min_len = before.len() + after.len();
283                     match *slice {
284                         Some(_) => cmp::max(min_len, size),
285                         None => min_len
286                     }
287                 }),
288                 _ => {
289                     let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
290                     tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
291                         ty: tcx.mk_slice(inner_ty),
292                         mutbl: expected_ty.builtin_deref(true).map(|mt| mt.mutbl)
293                                                               .unwrap_or(ast::MutImmutable)
294                     })
295                 }
296             };
297
298             fcx.write_ty(pat.id, pat_ty);
299
300             // `demand::subtype` would be good enough, but using
301             // `eqtype` turns out to be equally general. See (*)
302             // below for details.
303             demand::eqtype(fcx, pat.span, expected, pat_ty);
304
305             for elt in before {
306                 check_pat(pcx, &**elt, inner_ty);
307             }
308             if let Some(ref slice) = *slice {
309                 let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
310                 let mutbl = expected_ty.builtin_deref(true)
311                     .map_or(ast::MutImmutable, |mt| mt.mutbl);
312
313                 let slice_ty = tcx.mk_ref(tcx.mk_region(region), ty::TypeAndMut {
314                     ty: tcx.mk_slice(inner_ty),
315                     mutbl: mutbl
316                 });
317                 check_pat(pcx, &**slice, slice_ty);
318             }
319             for elt in after {
320                 check_pat(pcx, &**elt, inner_ty);
321             }
322         }
323         ast::PatMac(_) => tcx.sess.bug("unexpanded macro")
324     }
325
326
327     // (*) In most of the cases above (literals and constants being
328     // the exception), we relate types using strict equality, evewn
329     // though subtyping would be sufficient. There are a few reasons
330     // for this, some of which are fairly subtle and which cost me
331     // (nmatsakis) an hour or two debugging to remember, so I thought
332     // I'd write them down this time.
333     //
334     // 1. There is no loss of expressiveness here, though it does
335     // cause some inconvenience. What we are saying is that the type
336     // of `x` becomes *exactly* what is expected. This can cause unnecessary
337     // errors in some cases, such as this one:
338     // it will cause errors in a case like this:
339     //
340     // ```
341     // fn foo<'x>(x: &'x int) {
342     //    let a = 1;
343     //    let mut z = x;
344     //    z = &a;
345     // }
346     // ```
347     //
348     // The reason we might get an error is that `z` might be
349     // assigned a type like `&'x int`, and then we would have
350     // a problem when we try to assign `&a` to `z`, because
351     // the lifetime of `&a` (i.e., the enclosing block) is
352     // shorter than `'x`.
353     //
354     // HOWEVER, this code works fine. The reason is that the
355     // expected type here is whatever type the user wrote, not
356     // the initializer's type. In this case the user wrote
357     // nothing, so we are going to create a type variable `Z`.
358     // Then we will assign the type of the initializer (`&'x
359     // int`) as a subtype of `Z`: `&'x int <: Z`. And hence we
360     // will instantiate `Z` as a type `&'0 int` where `'0` is
361     // a fresh region variable, with the constraint that `'x :
362     // '0`.  So basically we're all set.
363     //
364     // Note that there are two tests to check that this remains true
365     // (`regions-reassign-{match,let}-bound-pointer.rs`).
366     //
367     // 2. Things go horribly wrong if we use subtype. The reason for
368     // THIS is a fairly subtle case involving bound regions. See the
369     // `givens` field in `region_inference`, as well as the test
370     // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
371     // for details. Short version is that we must sometimes detect
372     // relationships between specific region variables and regions
373     // bound in a closure signature, and that detection gets thrown
374     // off when we substitute fresh region variables here to enable
375     // subtyping.
376 }
377
378 fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
379     match def {
380         def::DefAssociatedConst(..) => true,
381         def::DefMethod(..) => {
382             span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
383                       "associated items in match patterns must be constants");
384             false
385         }
386         _ => {
387             pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in
388                                                  check_assoc_item_is_const");
389         }
390     }
391 }
392
393 pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
394                                       span: Span, expected: Ty<'tcx>,
395                                       inner: &ast::Pat) -> bool {
396     let fcx = pcx.fcx;
397     let tcx = pcx.fcx.ccx.tcx;
398     if pat_is_binding(&tcx.def_map, inner) {
399         let expected = fcx.infcx().shallow_resolve(expected);
400         expected.builtin_deref(true).map_or(true, |mt| match mt.ty.sty {
401             ty::TyTrait(_) => {
402                 // This is "x = SomeTrait" being reduced from
403                 // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
404                 span_err!(tcx.sess, span, E0033,
405                           "type `{}` cannot be dereferenced",
406                           fcx.infcx().ty_to_string(expected));
407                 false
408             }
409             _ => true
410         })
411     } else {
412         true
413     }
414 }
415
416 pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
417                              expr: &'tcx ast::Expr,
418                              discrim: &'tcx ast::Expr,
419                              arms: &'tcx [ast::Arm],
420                              expected: Expectation<'tcx>,
421                              match_src: ast::MatchSource) {
422     let tcx = fcx.ccx.tcx;
423
424     // Not entirely obvious: if matches may create ref bindings, we
425     // want to use the *precise* type of the discriminant, *not* some
426     // supertype, as the "discriminant type" (issue #23116).
427     let contains_ref_bindings = arms.iter()
428                                     .filter_map(|a| tcx.arm_contains_ref_binding(a))
429                                     .max_by(|m| match *m {
430                                         ast::MutMutable => 1,
431                                         ast::MutImmutable => 0,
432                                     });
433     let discrim_ty;
434     if let Some(m) = contains_ref_bindings {
435         check_expr_with_lvalue_pref(fcx, discrim, LvaluePreference::from_mutbl(m));
436         discrim_ty = fcx.expr_ty(discrim);
437     } else {
438         // ...but otherwise we want to use any supertype of the
439         // discriminant. This is sort of a workaround, see note (*) in
440         // `check_pat` for some details.
441         discrim_ty = fcx.infcx().next_ty_var();
442         check_expr_has_type(fcx, discrim, discrim_ty);
443     };
444
445     // Typecheck the patterns first, so that we get types for all the
446     // bindings.
447     for arm in arms {
448         let mut pcx = pat_ctxt {
449             fcx: fcx,
450             map: pat_id_map(&tcx.def_map, &*arm.pats[0]),
451         };
452         for p in &arm.pats {
453             check_pat(&mut pcx, &**p, discrim_ty);
454         }
455     }
456
457     // Now typecheck the blocks.
458     //
459     // The result of the match is the common supertype of all the
460     // arms. Start out the value as bottom, since it's the, well,
461     // bottom the type lattice, and we'll be moving up the lattice as
462     // we process each arm. (Note that any match with 0 arms is matching
463     // on any empty type and is therefore unreachable; should the flow
464     // of execution reach it, we will panic, so bottom is an appropriate
465     // type in that case)
466     let expected = expected.adjust_for_branches(fcx);
467     let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| {
468         let bty = match expected {
469             // We don't coerce to `()` so that if the match expression is a
470             // statement it's branches can have any consistent type. That allows
471             // us to give better error messages (pointing to a usually better
472             // arm for inconsistent arms or to the whole match when a `()` type
473             // is required).
474             Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => {
475                 check_expr_coercable_to_type(fcx, &*arm.body, ety);
476                 ety
477             }
478             _ => {
479                 check_expr_with_expectation(fcx, &*arm.body, expected);
480                 fcx.node_ty(arm.body.id)
481             }
482         };
483
484         if let Some(ref e) = arm.guard {
485             check_expr_has_type(fcx, &**e, tcx.types.bool);
486         }
487
488         if result_ty.references_error() || bty.references_error() {
489             tcx.types.err
490         } else {
491             let (origin, expected, found) = match match_src {
492                 /* if-let construct without an else block */
493                 ast::MatchSource::IfLetDesugar { contains_else_clause }
494                 if !contains_else_clause => (
495                     infer::IfExpressionWithNoElse(expr.span),
496                     bty,
497                     result_ty,
498                 ),
499                 _ => (
500                     infer::MatchExpressionArm(expr.span, arm.body.span),
501                     result_ty,
502                     bty,
503                 ),
504             };
505
506             infer::common_supertype(
507                 fcx.infcx(),
508                 origin,
509                 true,
510                 expected,
511                 found,
512             )
513         }
514     });
515
516     fcx.write_ty(expr.id, result_ty);
517 }
518
519 pub struct pat_ctxt<'a, 'tcx: 'a> {
520     pub fcx: &'a FnCtxt<'a, 'tcx>,
521     pub map: PatIdMap,
522 }
523
524 pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
525                                   path: &ast::Path, fields: &'tcx [Spanned<ast::FieldPat>],
526                                   etc: bool, expected: Ty<'tcx>) {
527     let fcx = pcx.fcx;
528     let tcx = pcx.fcx.ccx.tcx;
529
530     let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
531     let (enum_def_id, variant_def_id) = match def {
532         def::DefTrait(_) => {
533             let name = pprust::path_to_string(path);
534             span_err!(tcx.sess, pat.span, E0168,
535                 "use of trait `{}` in a struct pattern", name);
536             fcx.write_error(pat.id);
537
538             for field in fields {
539                 check_pat(pcx, &*field.node.pat, tcx.types.err);
540             }
541             return;
542         },
543         _ => {
544             let def_type = tcx.lookup_item_type(def.def_id());
545             match def_type.ty.sty {
546                 ty::TyStruct(struct_def_id, _) =>
547                     (struct_def_id, struct_def_id),
548                 ty::TyEnum(enum_def_id, _)
549                     if def == def::DefVariant(enum_def_id, def.def_id(), true) =>
550                     (enum_def_id, def.def_id()),
551                 _ => {
552                     let name = pprust::path_to_string(path);
553                     span_err!(tcx.sess, pat.span, E0163,
554                         "`{}` does not name a struct or a struct variant", name);
555                     fcx.write_error(pat.id);
556
557                     for field in fields {
558                         check_pat(pcx, &*field.node.pat, tcx.types.err);
559                     }
560                     return;
561                 }
562             }
563         }
564     };
565
566     instantiate_path(pcx.fcx,
567                      &path.segments,
568                      tcx.lookup_item_type(enum_def_id),
569                      &tcx.lookup_predicates(enum_def_id),
570                      None,
571                      def,
572                      pat.span,
573                      pat.id);
574
575     let pat_ty = fcx.node_ty(pat.id);
576     demand::eqtype(fcx, pat.span, expected, pat_ty);
577
578     let item_substs = fcx
579         .item_substs()
580         .get(&pat.id)
581         .map(|substs| substs.substs.clone())
582         .unwrap_or_else(|| Substs::empty());
583
584     let struct_fields = tcx.struct_fields(variant_def_id, &item_substs);
585     check_struct_pat_fields(pcx, pat.span, fields, &struct_fields,
586                             variant_def_id, etc);
587 }
588
589 pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
590                                 pat: &ast::Pat,
591                                 path: &ast::Path,
592                                 subpats: Option<&'tcx [P<ast::Pat>]>,
593                                 expected: Ty<'tcx>)
594 {
595     // Typecheck the path.
596     let fcx = pcx.fcx;
597     let tcx = pcx.fcx.ccx.tcx;
598
599     let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap();
600
601     let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
602                                                                 None, path,
603                                                                 pat.span, pat.id) {
604         Some(resolution) => resolution,
605         // Error handling done inside resolve_ty_and_def_ufcs, so if
606         // resolution fails just return.
607         None => {return;}
608     };
609
610     // Items that were partially resolved before should have been resolved to
611     // associated constants (i.e. not methods).
612     if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
613         fcx.write_error(pat.id);
614         return;
615     }
616
617     let enum_def = def.variant_def_ids()
618         .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
619
620     let ctor_scheme = tcx.lookup_item_type(enum_def);
621     let ctor_predicates = tcx.lookup_predicates(enum_def);
622     let path_scheme = if ctor_scheme.ty.is_fn() {
623         let fn_ret = tcx.no_late_bound_regions(&ctor_scheme.ty.fn_ret()).unwrap();
624         ty::TypeScheme {
625             ty: fn_ret.unwrap(),
626             generics: ctor_scheme.generics,
627         }
628     } else {
629         ctor_scheme
630     };
631     instantiate_path(pcx.fcx, segments,
632                      path_scheme, &ctor_predicates,
633                      opt_ty, def, pat.span, pat.id);
634
635     // If we didn't have a fully resolved path to start with, we had an
636     // associated const, and we should quit now, since the rest of this
637     // function uses checks specific to structs and enums.
638     if path_res.depth != 0 {
639         let pat_ty = fcx.node_ty(pat.id);
640         demand::suptype(fcx, pat.span, expected, pat_ty);
641         return;
642     }
643
644     let pat_ty = fcx.node_ty(pat.id);
645     demand::eqtype(fcx, pat.span, expected, pat_ty);
646
647
648     let real_path_ty = fcx.node_ty(pat.id);
649     let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
650         ty::TyEnum(enum_def_id, expected_substs)
651             if def == def::DefVariant(enum_def_id, def.def_id(), false) =>
652         {
653             let variant = tcx.enum_variant_with_id(enum_def_id, def.def_id());
654             (variant.args.iter()
655                          .map(|t| fcx.instantiate_type_scheme(pat.span, expected_substs, t))
656                          .collect(),
657              "variant")
658         }
659         ty::TyStruct(struct_def_id, expected_substs) => {
660             let struct_fields = tcx.struct_fields(struct_def_id, expected_substs);
661             (struct_fields.iter()
662                           .map(|field| fcx.instantiate_type_scheme(pat.span,
663                                                                    expected_substs,
664                                                                    &field.mt.ty))
665                           .collect(),
666              "struct")
667         }
668         _ => {
669             let name = pprust::path_to_string(path);
670             span_err!(tcx.sess, pat.span, E0164,
671                 "`{}` does not name a non-struct variant or a tuple struct", name);
672             fcx.write_error(pat.id);
673
674             if let Some(subpats) = subpats {
675                 for pat in subpats {
676                     check_pat(pcx, &**pat, tcx.types.err);
677                 }
678             }
679             return;
680         }
681     };
682
683     if let Some(subpats) = subpats {
684         if subpats.len() == arg_tys.len() {
685             for (subpat, arg_ty) in subpats.iter().zip(arg_tys) {
686                 check_pat(pcx, &**subpat, arg_ty);
687             }
688         } else if arg_tys.is_empty() {
689             span_err!(tcx.sess, pat.span, E0024,
690                       "this pattern has {} field{}, but the corresponding {} has no fields",
691                       subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name);
692
693             for pat in subpats {
694                 check_pat(pcx, &**pat, tcx.types.err);
695             }
696         } else {
697             span_err!(tcx.sess, pat.span, E0023,
698                       "this pattern has {} field{}, but the corresponding {} has {} field{}",
699                       subpats.len(), if subpats.len() == 1 {""} else {"s"},
700                       kind_name,
701                       arg_tys.len(), if arg_tys.len() == 1 {""} else {"s"});
702
703             for pat in subpats {
704                 check_pat(pcx, &**pat, tcx.types.err);
705             }
706         }
707     }
708 }
709
710 /// `path` is the AST path item naming the type of this struct.
711 /// `fields` is the field patterns of the struct pattern.
712 /// `struct_fields` describes the type of each field of the struct.
713 /// `struct_id` is the ID of the struct.
714 /// `etc` is true if the pattern said '...' and false otherwise.
715 pub fn check_struct_pat_fields<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
716                                          span: Span,
717                                          fields: &'tcx [Spanned<ast::FieldPat>],
718                                          struct_fields: &[ty::Field<'tcx>],
719                                          struct_id: ast::DefId,
720                                          etc: bool) {
721     let tcx = pcx.fcx.ccx.tcx;
722
723     // Index the struct fields' types.
724     let field_type_map = struct_fields
725         .iter()
726         .map(|field| (field.name, field.mt.ty))
727         .collect::<FnvHashMap<_, _>>();
728
729     // Keep track of which fields have already appeared in the pattern.
730     let mut used_fields = FnvHashMap();
731
732     // Typecheck each field.
733     for &Spanned { node: ref field, span } in fields {
734         let field_type = match used_fields.entry(field.ident.name) {
735             Occupied(occupied) => {
736                 span_err!(tcx.sess, span, E0025,
737                     "field `{}` bound multiple times in the pattern",
738                     field.ident);
739                 span_note!(tcx.sess, *occupied.get(),
740                     "field `{}` previously bound here",
741                     field.ident);
742                 tcx.types.err
743             }
744             Vacant(vacant) => {
745                 vacant.insert(span);
746                 field_type_map.get(&field.ident.name).cloned()
747                     .unwrap_or_else(|| {
748                         span_err!(tcx.sess, span, E0026,
749                             "struct `{}` does not have a field named `{}`",
750                             tcx.item_path_str(struct_id),
751                             field.ident);
752                         tcx.types.err
753                     })
754             }
755         };
756
757         let field_type = pcx.fcx.normalize_associated_types_in(span, &field_type);
758
759         check_pat(pcx, &*field.pat, field_type);
760     }
761
762     // Report an error if not all the fields were specified.
763     if !etc {
764         for field in struct_fields
765             .iter()
766             .filter(|field| !used_fields.contains_key(&field.name)) {
767             span_err!(tcx.sess, span, E0027,
768                 "pattern does not mention field `{}`",
769                 field.name);
770         }
771     }
772 }