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.
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.
11 use middle
::const_eval
;
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
;
26 use std
::cmp
::{self, Ordering}
;
27 use std
::collections
::hash_map
::Entry
::{Occupied, Vacant}
;
30 use syntax
::codemap
::{Span, Spanned}
;
31 use syntax
::parse
::token
;
32 use syntax
::print
::pprust
;
35 pub fn check_pat
<'a
, 'tcx
>(pcx
: &pat_ctxt
<'a
, 'tcx
>,
40 let tcx
= pcx
.fcx
.ccx
.tcx
;
42 debug
!("check_pat(pat={:?},expected={:?})",
48 fcx
.write_ty(pat
.id
, expected
);
50 ast
::PatLit(ref lt
) => {
51 check_expr(fcx
, &**lt
);
52 let expr_ty
= fcx
.expr_ty(&**lt
);
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 }
)
69 fcx
.write_ty(pat
.id
, pat_ty
);
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
80 // &'static str <: expected
82 // that's equivalent to there existing a LUB.
83 demand
::suptype(fcx
, pat
.span
, expected
, pat_ty
);
85 ast
::PatRange(ref begin
, ref end
) => {
86 check_expr(fcx
, begin
);
89 let lhs_ty
= fcx
.expr_ty(begin
);
90 let rhs_ty
= fcx
.expr_ty(end
);
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
);
97 if !lhs_compat
|| !rhs_compat
{
98 let span
= if !lhs_compat
&& !rhs_compat
{
100 } else if !lhs_compat
{
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
)
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()
122 // It's ok to return without a message as `require_same_types` prints an error.
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
);
131 fcx
.write_ty(pat
.id
, common_type
);
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");
142 None
=> tcx
.sess
.span_bug(begin
.span
, "literals of different types in range pat")
145 // subtyping doesn't matter here, as the value is some kind of scalar
146 demand
::eqtype(fcx
, pat
.span
, expected
, lhs_ty
);
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
,
155 fcx
.write_ty(pat
.id
, const_ty
);
157 // FIXME(#20489) -- we should limit the types here to scalars or something!
159 // As with PatLit, what we really want here is that there
160 // exist a LUB, but for the cases that can occur, subtype
162 demand
::suptype(fcx
, pat
.span
, expected
, const_ty
);
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
);
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
);
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
179 demand
::eqtype(fcx
, pat
.span
, region_ty
, typ
);
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
);
189 fcx
.write_ty(pat
.id
, typ
);
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
);
199 if let Some(ref p
) = *sub
{
200 check_pat(pcx
, &**p
, expected
);
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
);
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
);
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
) {
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()
223 tcx
.sess
.span_bug(pat
.span
,
224 &format
!("unbound path {:?}", pat
))
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
,
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
);
238 fcx
.write_error(pat
.id
)
242 ast
::PatStruct(ref path
, ref fields
, etc
) => {
243 check_pat_struct(pcx
, pat
, path
, fields
, etc
, expected
);
245 ast
::PatTup(ref elements
) => {
246 let element_tys
: Vec
<_
> =
247 (0..elements
.len()).map(|_
| fcx
.infcx().next_ty_var())
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
);
256 ast
::PatBox(ref inner
) => {
257 let inner_ty
= fcx
.infcx().next_ty_var();
258 let uniq_ty
= ty
::mk_uniq(tcx
, inner_ty
);
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
264 demand
::eqtype(fcx
, pat
.span
, expected
, uniq_ty
);
265 fcx
.write_ty(pat
.id
, uniq_ty
);
266 check_pat(pcx
, &**inner
, inner_ty
);
268 fcx
.write_error(pat
.id
);
269 check_pat(pcx
, &**inner
, tcx
.types
.err
);
272 ast
::PatRegion(ref inner
, mutbl
) => {
273 let inner_ty
= fcx
.infcx().next_ty_var();
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
);
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
);
287 fcx
.write_error(pat
.id
);
288 check_pat(pcx
, &**inner
, tcx
.types
.err
);
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();
298 Some(_
) => cmp
::max(min_len
, size
),
303 let region
= fcx
.infcx().next_region_var(infer
::PatternRegion(pat
.span
));
304 ty
::mk_slice(tcx
, tcx
.mk_region(region
), ty
::mt
{
306 mutbl
: ty
::deref(expected_ty
, true).map(|mt
| mt
.mutbl
)
307 .unwrap_or(ast
::MutImmutable
)
312 fcx
.write_ty(pat
.id
, pat_ty
);
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
);
320 check_pat(pcx
, &**elt
, inner_ty
);
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
);
327 let slice_ty
= ty
::mk_slice(tcx
, tcx
.mk_region(region
), ty
::mt
{
331 check_pat(pcx
, &**slice
, slice_ty
);
334 check_pat(pcx
, &**elt
, inner_ty
);
337 ast
::PatMac(_
) => tcx
.sess
.bug("unexpanded macro")
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.
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:
355 // fn foo<'x>(x: &'x int) {
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`.
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.
378 // Note that there are two tests to check that this remains true
379 // (`regions-reassign-{match,let}-bound-pointer.rs`).
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
392 fn check_assoc_item_is_const(pcx
: &pat_ctxt
, def
: def
::Def
, span
: Span
) -> bool
{
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");
401 pcx
.fcx
.ccx
.tcx
.sess
.span_bug(span
, "non-associated item in
402 check_assoc_item_is_const");
407 pub fn check_dereferencable
<'a
, 'tcx
>(pcx
: &pat_ctxt
<'a
, 'tcx
>,
408 span
: Span
, expected
: Ty
<'tcx
>,
409 inner
: &ast
::Pat
) -> bool
{
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
{
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
));
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
;
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,
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
);
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
);
459 // Typecheck the patterns first, so that we get types for all the
462 let mut pcx
= pat_ctxt
{
464 map
: pat_id_map(&tcx
.def_map
, &*arm
.pats
[0]),
467 check_pat(&mut pcx
, &**p
, discrim_ty
);
471 // Now typecheck the blocks.
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
488 Expectation
::ExpectHasType(ety
) if ety
!= ty
::mk_nil(fcx
.tcx()) => {
489 check_expr_coercable_to_type(fcx
, &*arm
.body
, ety
);
493 check_expr_with_expectation(fcx
, &*arm
.body
, expected
);
494 fcx
.node_ty(arm
.body
.id
)
498 if let Some(ref e
) = arm
.guard
{
499 check_expr_has_type(fcx
, &**e
, tcx
.types
.bool
);
502 if ty
::type_is_error(result_ty
) || ty
::type_is_error(bty
) {
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
),
514 infer
::MatchExpressionArm(expr
.span
, arm
.body
.span
),
520 infer
::common_supertype(
530 fcx
.write_ty(expr
.id
, result_ty
);
533 pub struct pat_ctxt
<'a
, 'tcx
: 'a
> {
534 pub fcx
: &'a FnCtxt
<'a
, 'tcx
>,
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
>) {
542 let tcx
= pcx
.fcx
.ccx
.tcx
;
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
);
552 for field
in fields
{
553 check_pat(pcx
, &*field
.node
.pat
, tcx
.types
.err
);
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()),
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
);
571 for field
in fields
{
572 check_pat(pcx
, &*field
.node
.pat
, tcx
.types
.err
);
580 instantiate_path(pcx
.fcx
,
582 ty
::lookup_item_type(tcx
, enum_def_id
),
583 &ty
::lookup_predicates(tcx
, enum_def_id
),
589 let pat_ty
= fcx
.node_ty(pat
.id
);
590 demand
::eqtype(fcx
, pat
.span
, expected
, pat_ty
);
592 let item_substs
= fcx
595 .map(|substs
| substs
.substs
.clone())
596 .unwrap_or_else(|| Substs
::empty());
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
);
603 pub fn check_pat_enum
<'a
, 'tcx
>(pcx
: &pat_ctxt
<'a
, 'tcx
>,
606 subpats
: Option
<&'tcx
[P
<ast
::Pat
>]>,
609 // Typecheck the path.
611 let tcx
= pcx
.fcx
.ccx
.tcx
;
613 let path_res
= *tcx
.def_map
.borrow().get(&pat
.id
).unwrap();
615 let (opt_ty
, segments
, def
) = match resolve_ty_and_def_ufcs(fcx
, path_res
,
618 Some(resolution
) => resolution
,
619 // Error handling done inside resolve_ty_and_def_ufcs, so if
620 // resolution fails just return.
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
);
631 let enum_def
= def
.variant_def_ids()
632 .map_or_else(|| def
.def_id(), |(enum_def
, _
)| enum_def
);
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();
640 generics
: ctor_scheme
.generics
,
645 instantiate_path(pcx
.fcx
, segments
,
646 path_scheme
, &ctor_predicates
,
647 opt_ty
, def
, pat
.span
, pat
.id
);
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
);
658 let pat_ty
= fcx
.node_ty(pat
.id
);
659 demand
::eqtype(fcx
, pat
.span
, expected
, pat_ty
);
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) =>
667 let variant
= ty
::enum_variant_with_id(tcx
, enum_def_id
, def
.def_id());
669 .map(|t
| fcx
.instantiate_type_scheme(pat
.span
, expected_substs
, t
))
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
,
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
);
688 if let Some(subpats
) = subpats
{
690 check_pat(pcx
, &**pat
, tcx
.types
.err
);
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
);
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
);
708 check_pat(pcx
, &**pat
, tcx
.types
.err
);
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"}
,
715 arg_tys
.len(), if arg_tys
.len() == 1 {""}
else {"s"}
);
718 check_pat(pcx
, &**pat
, tcx
.types
.err
);
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
>,
731 fields
: &'tcx
[Spanned
<ast
::FieldPat
>],
732 struct_fields
: &[ty
::field
<'tcx
>],
733 struct_id
: ast
::DefId
,
735 let tcx
= pcx
.fcx
.ccx
.tcx
;
737 // Index the struct fields' types.
738 let field_type_map
= struct_fields
740 .map(|field
| (field
.name
, field
.mt
.ty
))
741 .collect
::<FnvHashMap
<_
, _
>>();
743 // Keep track of which fields have already appeared in the pattern.
744 let mut used_fields
= FnvHashMap();
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
));
760 field_type_map
.get(&field
.ident
.name
).cloned()
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
));
771 let field_type
= pcx
.fcx
.normalize_associated_types_in(span
, &field_type
);
773 check_pat(pcx
, &*field
.pat
, field_type
);
776 // Report an error if not all the fields were specified.
778 for field
in struct_fields
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
));