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