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