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 #![allow(non_camel_case_types)]
14 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
16 use middle::subst::Subst;
18 use middle::typeck::check::demand;
19 use middle::typeck::check::{check_expr, check_expr_has_type, FnCtxt};
20 use middle::typeck::check::{instantiate_path, lookup_def};
21 use middle::typeck::check::{structure_of, valid_range_bounds};
22 use middle::typeck::infer;
23 use middle::typeck::require_same_types;
25 use std::collections::{HashMap, HashSet};
29 use syntax::parse::token;
30 use syntax::codemap::Span;
31 use syntax::print::pprust;
33 pub fn check_match(fcx: &FnCtxt,
37 let tcx = fcx.ccx.tcx;
39 let discrim_ty = fcx.infcx().next_ty_var();
40 check_expr_has_type(fcx, discrim, discrim_ty);
42 // Typecheck the patterns first, so that we get types for all the
44 for arm in arms.iter() {
45 let mut pcx = pat_ctxt {
47 map: pat_id_map(&tcx.def_map, &**arm.pats.get(0)),
50 for p in arm.pats.iter() { check_pat(&mut pcx, &**p, discrim_ty);}
53 // The result of the match is the common supertype of all the
54 // arms. Start out the value as bottom, since it's the, well,
55 // bottom the type lattice, and we'll be moving up the lattice as
56 // we process each arm. (Note that any match with 0 arms is matching
57 // on any empty type and is therefore unreachable; should the flow
58 // of execution reach it, we will fail, so bottom is an appropriate
60 let mut result_ty = ty::mk_bot();
62 // Now typecheck the blocks.
63 let mut saw_err = ty::type_is_error(discrim_ty);
64 for arm in arms.iter() {
65 let mut guard_err = false;
66 let mut guard_bot = false;
69 check_expr_has_type(fcx, &**e, ty::mk_bool());
70 let e_ty = fcx.expr_ty(&**e);
71 if ty::type_is_error(e_ty) {
74 else if ty::type_is_bot(e_ty) {
80 check_expr(fcx, &*arm.body);
81 let bty = fcx.node_ty(arm.body.id);
82 saw_err = saw_err || ty::type_is_error(bty);
84 fcx.write_error(arm.body.id);
88 fcx.write_bot(arm.body.id);
92 infer::common_supertype(
94 infer::MatchExpressionArm(expr.span, arm.body.span),
95 true, // result_ty is "expected" here
101 result_ty = ty::mk_err();
102 } else if ty::type_is_bot(discrim_ty) {
103 result_ty = ty::mk_bot();
106 fcx.write_ty(expr.id, result_ty);
109 pub struct pat_ctxt<'a> {
110 pub fcx: &'a FnCtxt<'a>,
114 pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
115 subpats: &Option<Vec<Gc<ast::Pat>>>, expected: ty::t) {
117 // Typecheck the path.
119 let tcx = pcx.fcx.ccx.tcx;
121 let arg_types: Vec<ty::t> ;
124 // structure_of requires type variables to be resolved.
125 // So when we pass in <expected>, it's an error if it
126 // contains type variables.
128 // Check to see whether this is an enum or a struct.
129 match *structure_of(pcx.fcx, pat.span, expected) {
130 ty::ty_enum(expected_def_id, ref expected_substs) => {
131 // Lookup the enum and variant def ids:
132 let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
133 match v_def.variant_def_ids() {
134 Some((enm, var)) => {
135 // Assign the pattern the type of the *enum*, not the variant.
136 let enum_pty = ty::lookup_item_type(tcx, enm);
137 instantiate_path(pcx.fcx,
144 // check that the type of the value being matched is a subtype
145 // of the type of the pattern:
146 let pat_ty = fcx.node_ty(pat.id);
147 demand::subtype(fcx, pat.span, expected, pat_ty);
149 // Get the expected types of the arguments.
152 ty::enum_variant_with_id(tcx, enm, var);
153 if enm == expected_def_id {
155 .map(|t| t.subst(tcx, expected_substs))
159 .map(|_| ty::mk_err())
164 kind_name = "variant";
167 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
168 fcx.infcx().type_error_message_str_with_expected(pat.span,
170 expected.map_or("".to_string(), |e| {
171 format!("mismatched types: expected `{}` but found {}",
175 "a structure pattern".to_string(),
177 fcx.write_error(pat.id);
178 kind_name = "[error]";
179 arg_types = subpats.clone()
182 .map(|_| ty::mk_err())
187 ty::ty_struct(struct_def_id, ref expected_substs) => {
188 // Lookup the struct ctor def id
189 let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
190 let s_def_id = s_def.def_id();
192 // Assign the pattern the type of the struct.
193 let ctor_pty = ty::lookup_item_type(tcx, s_def_id);
194 let struct_pty = if ty::is_fn_ty(ctor_pty.ty) {
195 ty::Polytype {ty: ty::ty_fn_ret(ctor_pty.ty),
200 instantiate_path(pcx.fcx,
207 // Check that the type of the value being matched is a subtype of
208 // the type of the pattern.
209 let pat_ty = fcx.node_ty(pat.id);
210 demand::subtype(fcx, pat.span, expected, pat_ty);
212 // Get the expected types of the arguments.
213 let class_fields = ty::struct_fields(
214 tcx, struct_def_id, expected_substs);
215 arg_types = class_fields.iter().map(|field| field.mt.ty).collect();
217 kind_name = "structure";
220 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
221 fcx.infcx().type_error_message_str_with_expected(pat.span,
223 expected.map_or("".to_string(),
225 format!("mismatched types: expected `{}` but found {}",
230 "an enum or structure pattern".to_string(),
232 fcx.write_error(pat.id);
233 kind_name = "[error]";
234 arg_types = subpats.clone()
237 .map(|_| ty::mk_err())
242 let arg_len = arg_types.len();
244 // Count the number of subpatterns.
247 None => subpats_len = arg_len,
248 Some(ref subpats) => subpats_len = subpats.len()
251 let mut error_happened = false;
255 if arg_len != subpats_len {
256 let s = format!("this pattern has {} field{}, \
257 but the corresponding {} has {} field{}",
259 if subpats_len == 1 {""} else {"s"},
262 if arg_len == 1 {""} else {"s"});
263 tcx.sess.span_err(pat.span, s.as_slice());
264 error_happened = true;
268 for pats in subpats.iter() {
269 for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
270 check_pat(pcx, &**subpat, *arg_ty);
274 } else if subpats_len > 0 {
275 tcx.sess.span_err(pat.span,
276 format!("this pattern has {} field{}, \
277 but the corresponding {} has no fields",
279 if subpats_len == 1 {""} else {"s"},
280 kind_name).as_slice());
281 error_happened = true;
285 for pats in subpats.iter() {
286 for pat in pats.iter() {
287 check_pat(pcx, &**pat, ty::mk_err());
293 /// `path` is the AST path item naming the type of this struct.
294 /// `fields` is the field patterns of the struct pattern.
295 /// `class_fields` describes the type of each field of the struct.
296 /// `class_id` is the ID of the struct.
297 /// `substitutions` are the type substitutions applied to this struct type
298 /// (e.g. K,V in HashMap<K,V>).
299 /// `etc` is true if the pattern said '...' and false otherwise.
300 pub fn check_struct_pat_fields(pcx: &pat_ctxt,
302 fields: &[ast::FieldPat],
303 class_fields: Vec<ty::field_ty>,
304 class_id: ast::DefId,
305 substitutions: &subst::Substs,
307 let tcx = pcx.fcx.ccx.tcx;
309 // Index the class fields. The second argument in the tuple is whether the
310 // field has been bound yet or not.
311 let mut field_map = HashMap::new();
312 for (i, class_field) in class_fields.iter().enumerate() {
313 field_map.insert(class_field.name, (i, false));
316 // Typecheck each field.
317 let mut found_fields = HashSet::new();
318 for field in fields.iter() {
319 match field_map.find_mut(&field.ident.name) {
320 Some(&(_, true)) => {
321 tcx.sess.span_err(span,
322 format!("field `{}` bound twice in pattern",
323 token::get_ident(field.ident)).as_slice());
325 Some(&(index, ref mut used)) => {
327 let class_field = *class_fields.get(index);
328 let field_type = ty::lookup_field_type(tcx,
332 check_pat(pcx, &*field.pat, field_type);
333 found_fields.insert(index);
336 // Check the pattern anyway, so that attempts to look
337 // up its type won't fail
338 check_pat(pcx, &*field.pat, ty::mk_err());
339 tcx.sess.span_err(span,
340 format!("struct `{}` does not have a field named `{}`",
341 ty::item_path_str(tcx, class_id),
342 token::get_ident(field.ident)).as_slice());
347 // Report an error if not all the fields were specified.
349 for (i, field) in class_fields.iter().enumerate() {
350 if found_fields.contains(&i) {
356 format!("pattern does not mention field `{}`",
357 token::get_name(field.name)).as_slice());
362 pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: Span,
363 expected: ty::t, path: &ast::Path,
364 fields: &[ast::FieldPat], etc: bool,
365 struct_id: ast::DefId,
366 substitutions: &subst::Substs) {
368 let tcx = pcx.fcx.ccx.tcx;
370 let class_fields = ty::lookup_struct_fields(tcx, struct_id);
372 // Check to ensure that the struct is the one specified.
373 match tcx.def_map.borrow().find(&pat_id) {
374 Some(&def::DefStruct(supplied_def_id))
375 if supplied_def_id == struct_id => {
378 Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => {
379 let name = pprust::path_to_str(path);
382 format!("mismatched types: expected `{}` but found \
384 fcx.infcx().ty_to_str(expected),
388 tcx.sess.span_bug(span, "resolve didn't write in struct ID");
392 check_struct_pat_fields(pcx, span, fields, class_fields, struct_id,
396 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
401 fields: &[ast::FieldPat],
404 substitutions: &subst::Substs) {
406 let tcx = pcx.fcx.ccx.tcx;
408 // Find the variant that was specified.
409 match tcx.def_map.borrow().find(&pat_id) {
410 Some(&def::DefVariant(found_enum_id, variant_id, _))
411 if found_enum_id == enum_id => {
412 // Get the struct fields from this struct-like enum variant.
413 let class_fields = ty::lookup_struct_fields(tcx, variant_id);
415 check_struct_pat_fields(pcx, span, fields, class_fields,
416 variant_id, substitutions, etc);
418 Some(&def::DefStruct(..)) | Some(&def::DefVariant(..)) => {
419 let name = pprust::path_to_str(path);
420 tcx.sess.span_err(span,
421 format!("mismatched types: expected `{}` but \
423 fcx.infcx().ty_to_str(expected),
427 tcx.sess.span_bug(span, "resolve didn't write in variant");
432 // Pattern checking is top-down rather than bottom-up so that bindings get
433 // their types immediately.
434 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
436 let tcx = pcx.fcx.ccx.tcx;
439 ast::PatWild | ast::PatWildMulti => {
440 fcx.write_ty(pat.id, expected);
442 ast::PatLit(ref lt) => {
443 check_expr_has_type(fcx, &**lt, expected);
444 fcx.write_ty(pat.id, fcx.expr_ty(&**lt));
446 ast::PatRange(ref begin, ref end) => {
447 check_expr_has_type(fcx, &**begin, expected);
448 check_expr_has_type(fcx, &**end, expected);
450 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**begin));
452 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**end));
453 debug!("pat_range beginning type: {:?}", b_ty);
454 debug!("pat_range ending type: {:?}", e_ty);
455 if !require_same_types(
456 tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
457 || "mismatched types in range".to_string())
460 } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
461 tcx.sess.span_err(pat.span,
462 "only char and numeric types are allowed in range");
464 match valid_range_bounds(fcx.ccx, &**begin, &**end) {
466 tcx.sess.span_err(begin.span,
467 "lower range bound must be less than upper");
470 tcx.sess.span_err(begin.span,
471 "mismatched types in range");
476 fcx.write_ty(pat.id, b_ty);
479 ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
480 let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
481 let const_pty = ty::lookup_item_type(tcx, const_did);
482 demand::suptype(fcx, pat.span, expected, const_pty.ty);
483 fcx.write_ty(pat.id, const_pty.ty);
485 ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
486 let typ = fcx.local_ty(pat.span, pat.id);
489 ast::BindByRef(mutbl) => {
490 // if the binding is like
491 // ref x | ref const x | ref mut x
492 // then the type of x is &M T where M is the mutability
493 // and T is the expected type
495 fcx.infcx().next_region_var(
496 infer::PatternRegion(pat.span));
497 let mt = ty::mt {ty: expected, mutbl: mutbl};
498 let region_ty = ty::mk_rptr(tcx, region_var, mt);
499 demand::eqtype(fcx, pat.span, region_ty, typ);
501 // otherwise the type of x is the expected type T
502 ast::BindByValue(_) => {
503 demand::eqtype(fcx, pat.span, expected, typ);
507 let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
508 if canon_id != pat.id {
509 let ct = fcx.local_ty(pat.span, canon_id);
510 demand::eqtype(fcx, pat.span, ct, typ);
512 fcx.write_ty(pat.id, typ);
514 debug!("(checking match) writing type for pat id {}", pat.id);
517 Some(ref p) => check_pat(pcx, &**p, expected),
521 ast::PatIdent(_, ref path, _) => {
522 check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
524 ast::PatEnum(ref path, ref subpats) => {
525 check_pat_variant(pcx, pat, path, subpats, expected);
527 ast::PatStruct(ref path, ref fields, etc) => {
528 // Grab the class data that we care about.
529 let structure = structure_of(fcx, pat.span, expected);
530 let mut error_happened = false;
532 ty::ty_struct(cid, ref substs) => {
533 check_struct_pat(pcx, pat.id, pat.span, expected, path,
534 fields.as_slice(), etc, cid, substs);
536 ty::ty_enum(eid, ref substs) => {
537 check_struct_like_enum_variant_pat(pcx,
548 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
549 fcx.infcx().type_error_message_str_with_expected(pat.span,
551 expected.map_or("".to_string(),
553 format!("mismatched types: expected \
554 `{}` but found {}", e, actual)
557 "a structure pattern".to_string(),
559 match tcx.def_map.borrow().find(&pat.id) {
560 Some(&def::DefStruct(supplied_def_id)) => {
561 check_struct_pat(pcx,
569 &subst::Substs::empty());
571 _ => () // Error, but we're already in an error case
573 error_happened = true;
577 // Finally, write in the type.
579 fcx.write_error(pat.id);
581 fcx.write_ty(pat.id, expected);
584 ast::PatTup(ref elts) => {
585 let s = structure_of(fcx, pat.span, expected);
586 let e_count = elts.len();
588 ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
589 for (i, elt) in elts.iter().enumerate() {
590 check_pat(pcx, &**elt, *ex_elts.get(i));
592 fcx.write_ty(pat.id, expected);
595 for elt in elts.iter() {
596 check_pat(pcx, &**elt, ty::mk_err());
598 // use terr_tuple_size if both types are tuples
599 let type_error = match *s {
600 ty::ty_tup(ref ex_elts) => {
601 ty::terr_tuple_size(ty::expected_found {
602 expected: ex_elts.len(),
606 _ => ty::terr_mismatch
608 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
609 fcx.infcx().type_error_message_str_with_expected(pat.span,
612 expected.map_or("".to_string(), |e| {
613 format!("mismatched types: expected `{}` \
614 but found {}", e, actual)
620 fcx.write_error(pat.id);
624 ast::PatBox(ref inner) => {
625 check_pointer_pat(pcx, Send, &**inner, pat.id, pat.span, expected);
627 ast::PatRegion(ref inner) => {
628 check_pointer_pat(pcx, Borrowed, &**inner, pat.id, pat.span, expected);
630 ast::PatVec(ref before, slice, ref after) => {
631 let default_region_var =
632 fcx.infcx().next_region_var(
633 infer::PatternRegion(pat.span));
635 let check_err = |found: String| {
636 for &elt in before.iter() {
637 check_pat(pcx, &*elt, ty::mk_err());
639 for elt in slice.iter() {
640 check_pat(pcx, &**elt, ty::mk_err());
642 for elt in after.iter() {
643 check_pat(pcx, &**elt, ty::mk_err());
645 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
646 fcx.infcx().type_error_message_str_with_expected(
649 expected.map_or("".to_string(),
651 format!("mismatched types: expected `{}` but found {}",
658 fcx.write_error(pat.id);
661 let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
664 ty::ty_vec(mt, Some(fixed)) =>
665 (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
666 ty::ty_uniq(t) => match ty::get(t).sty {
667 ty::ty_vec(mt, None) => {
668 fcx.type_error_message(pat.span,
670 "unique vector patterns are no \
671 longer supported".to_string()
675 (mt.ty, default_region_var, ast::MutImmutable, None)
678 check_err("a vector pattern".to_string());
682 ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
683 ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
685 check_err("a vector pattern".to_string());
690 check_err("a vector pattern".to_string());
695 let min_len = before.len() + after.len();
696 fixed.and_then(|count| match slice {
697 Some(_) if count < min_len =>
698 Some(format!("a fixed vector pattern of size at least {}", min_len)),
700 None if count != min_len =>
701 Some(format!("a fixed vector pattern of size {}", min_len)),
706 for elt in before.iter() {
707 check_pat(pcx, &**elt, elt_type);
710 Some(ref slice_pat) => {
711 let slice_ty = ty::mk_slice(tcx,
713 ty::mt {ty: elt_type, mutbl: mutbl});
714 check_pat(pcx, &**slice_pat, slice_ty);
718 for elt in after.iter() {
719 check_pat(pcx, &**elt, elt_type);
721 fcx.write_ty(pat.id, expected);
724 ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
728 // Helper function to check gc, box and & patterns
729 pub fn check_pointer_pat(pcx: &pat_ctxt,
730 pointer_kind: PointerKind,
736 let check_inner: |ty::t| = |e_inner| {
737 check_pat(pcx, inner, e_inner);
738 fcx.write_ty(pat_id, expected);
740 match *structure_of(fcx, span, expected) {
741 ty::ty_uniq(e_inner) if pointer_kind == Send && !ty::type_is_trait(e_inner) => {
742 check_inner(e_inner);
744 ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed && !ty::type_is_trait(e_inner.ty) => {
745 check_inner(e_inner.ty);
748 check_pat(pcx, inner, ty::mk_err());
749 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
750 fcx.infcx().type_error_message_str_with_expected(
753 expected.map_or("".to_string(), |e| {
754 format!("mismatched types: expected `{}` but found {}",
759 format!("{} pattern", match pointer_kind {
761 Borrowed => "an `&`-pointer",
764 fcx.write_error(pat_id);
769 #[deriving(PartialEq)]
770 pub enum PointerKind {