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