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;
26 use std::collections::{HashMap, HashSet};
30 use syntax::parse::token;
31 use syntax::codemap::Span;
32 use syntax::print::pprust;
34 pub fn check_match(fcx: &FnCtxt,
38 let tcx = fcx.ccx.tcx;
40 let discrim_ty = fcx.infcx().next_ty_var();
41 check_expr_has_type(fcx, discrim, discrim_ty);
43 // Typecheck the patterns first, so that we get types for all the
45 for arm in arms.iter() {
46 let mut pcx = pat_ctxt {
48 map: pat_id_map(&tcx.def_map, &**arm.pats.get(0)),
51 for p in arm.pats.iter() { check_pat(&mut pcx, &**p, discrim_ty);}
54 // The result of the match is the common supertype of all the
55 // arms. Start out the value as bottom, since it's the, well,
56 // bottom the type lattice, and we'll be moving up the lattice as
57 // we process each arm. (Note that any match with 0 arms is matching
58 // on any empty type and is therefore unreachable; should the flow
59 // of execution reach it, we will fail, so bottom is an appropriate
61 let mut result_ty = ty::mk_bot();
63 // Now typecheck the blocks.
64 let mut saw_err = ty::type_is_error(discrim_ty);
65 for arm in arms.iter() {
66 let mut guard_err = false;
67 let mut guard_bot = false;
70 check_expr_has_type(fcx, &**e, ty::mk_bool());
71 let e_ty = fcx.expr_ty(&**e);
72 if ty::type_is_error(e_ty) {
75 else if ty::type_is_bot(e_ty) {
81 check_expr(fcx, &*arm.body);
82 let bty = fcx.node_ty(arm.body.id);
83 saw_err = saw_err || ty::type_is_error(bty);
85 fcx.write_error(arm.body.id);
89 fcx.write_bot(arm.body.id);
93 infer::common_supertype(
95 infer::MatchExpressionArm(expr.span, arm.body.span),
96 true, // result_ty is "expected" here
102 result_ty = ty::mk_err();
103 } else if ty::type_is_bot(discrim_ty) {
104 result_ty = ty::mk_bot();
107 fcx.write_ty(expr.id, result_ty);
110 pub struct pat_ctxt<'a> {
111 pub fcx: &'a FnCtxt<'a>,
115 pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
116 subpats: &Option<Vec<Gc<ast::Pat>>>, expected: ty::t) {
118 // Typecheck the path.
120 let tcx = pcx.fcx.ccx.tcx;
122 let arg_types: Vec<ty::t> ;
125 // structure_of requires type variables to be resolved.
126 // So when we pass in <expected>, it's an error if it
127 // contains type variables.
129 // Check to see whether this is an enum or a struct.
130 match *structure_of(pcx.fcx, pat.span, expected) {
131 ty::ty_enum(expected_def_id, ref expected_substs) => {
132 // Lookup the enum and variant def ids:
133 let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
134 match v_def.variant_def_ids() {
135 Some((enm, var)) => {
136 // Assign the pattern the type of the *enum*, not the variant.
137 let enum_pty = ty::lookup_item_type(tcx, enm);
138 instantiate_path(pcx.fcx,
145 // check that the type of the value being matched is a subtype
146 // of the type of the pattern:
147 let pat_ty = fcx.node_ty(pat.id);
148 demand::subtype(fcx, pat.span, expected, pat_ty);
150 // Get the expected types of the arguments.
153 ty::enum_variant_with_id(tcx, enm, var);
154 if enm == expected_def_id {
156 .map(|t| t.subst(tcx, expected_substs))
160 .map(|_| ty::mk_err())
165 kind_name = "variant";
168 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
169 fcx.infcx().type_error_message_str_with_expected(pat.span,
171 expected.map_or("".to_string(), |e| {
172 format!("mismatched types: expected `{}` but found {}",
176 "a structure pattern".to_string(),
178 fcx.write_error(pat.id);
179 kind_name = "[error]";
180 arg_types = subpats.clone()
183 .map(|_| ty::mk_err())
188 ty::ty_struct(struct_def_id, ref expected_substs) => {
189 // Lookup the struct ctor def id
190 let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
191 let s_def_id = s_def.def_id();
193 // Assign the pattern the type of the struct.
194 let ctor_pty = ty::lookup_item_type(tcx, s_def_id);
195 let struct_pty = if ty::is_fn_ty(ctor_pty.ty) {
196 ty::Polytype {ty: ty::ty_fn_ret(ctor_pty.ty),
201 instantiate_path(pcx.fcx,
208 // Check that the type of the value being matched is a subtype of
209 // the type of the pattern.
210 let pat_ty = fcx.node_ty(pat.id);
211 demand::subtype(fcx, pat.span, expected, pat_ty);
213 // Get the expected types of the arguments.
214 let class_fields = ty::struct_fields(
215 tcx, struct_def_id, expected_substs);
216 arg_types = class_fields.iter().map(|field| field.mt.ty).collect();
218 kind_name = "structure";
221 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
222 fcx.infcx().type_error_message_str_with_expected(pat.span,
224 expected.map_or("".to_string(),
226 format!("mismatched types: expected `{}` but found {}",
231 "an enum or structure pattern".to_string(),
233 fcx.write_error(pat.id);
234 kind_name = "[error]";
235 arg_types = subpats.clone()
238 .map(|_| ty::mk_err())
243 let arg_len = arg_types.len();
245 // Count the number of subpatterns.
248 None => subpats_len = arg_len,
249 Some(ref subpats) => subpats_len = subpats.len()
252 let mut error_happened = false;
256 if arg_len != subpats_len {
257 span_err!(tcx.sess, pat.span, E0023,
258 "this pattern has {} field{}, but the corresponding {} has {} field{}",
259 subpats_len, if subpats_len == 1 {""} else {"s"},
260 kind_name, arg_len, if arg_len == 1 {""} else {"s"});
261 error_happened = true;
265 for pats in subpats.iter() {
266 for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
267 check_pat(pcx, &**subpat, *arg_ty);
271 } else if subpats_len > 0 {
272 span_err!(tcx.sess, pat.span, E0024,
273 "this pattern has {} field{}, but the corresponding {} has no fields",
274 subpats_len, if subpats_len == 1 {""} else {"s"},
276 error_happened = true;
280 for pats in subpats.iter() {
281 for pat in pats.iter() {
282 check_pat(pcx, &**pat, ty::mk_err());
288 /// `path` is the AST path item naming the type of this struct.
289 /// `fields` is the field patterns of the struct pattern.
290 /// `class_fields` describes the type of each field of the struct.
291 /// `class_id` is the ID of the struct.
292 /// `substitutions` are the type substitutions applied to this struct type
293 /// (e.g. K,V in HashMap<K,V>).
294 /// `etc` is true if the pattern said '...' and false otherwise.
295 pub fn check_struct_pat_fields(pcx: &pat_ctxt,
297 fields: &[ast::FieldPat],
298 class_fields: Vec<ty::field_ty>,
299 class_id: ast::DefId,
300 substitutions: &subst::Substs,
302 let tcx = pcx.fcx.ccx.tcx;
304 // Index the class fields. The second argument in the tuple is whether the
305 // field has been bound yet or not.
306 let mut field_map = HashMap::new();
307 for (i, class_field) in class_fields.iter().enumerate() {
308 field_map.insert(class_field.name, (i, false));
311 // Typecheck each field.
312 let mut found_fields = HashSet::new();
313 for field in fields.iter() {
314 match field_map.find_mut(&field.ident.name) {
315 Some(&(_, true)) => {
316 // Check the pattern anyway, so that attempts to look
317 // up its type won't fail
318 check_pat(pcx, &*field.pat, ty::mk_err());
319 span_err!(tcx.sess, span, E0025,
320 "field `{}` bound twice in pattern",
321 token::get_ident(field.ident));
323 Some(&(index, ref mut used)) => {
325 let class_field = *class_fields.get(index);
326 let field_type = ty::lookup_field_type(tcx,
330 check_pat(pcx, &*field.pat, field_type);
331 found_fields.insert(index);
334 // Check the pattern anyway, so that attempts to look
335 // up its type won't fail
336 check_pat(pcx, &*field.pat, ty::mk_err());
337 span_err!(tcx.sess, span, E0026,
338 "struct `{}` does not have a field named `{}`",
339 ty::item_path_str(tcx, class_id),
340 token::get_ident(field.ident));
345 // Report an error if not all the fields were specified.
347 for (i, field) in class_fields.iter().enumerate() {
348 if found_fields.contains(&i) {
351 span_err!(tcx.sess, span, E0027,
352 "pattern does not mention field `{}`",
353 token::get_name(field.name));
358 pub fn check_struct_pat(pcx: &pat_ctxt, _pat_id: ast::NodeId, span: Span,
359 _expected: ty::t, _path: &ast::Path,
360 fields: &[ast::FieldPat], etc: bool,
361 struct_id: ast::DefId,
362 substitutions: &subst::Substs) {
364 let tcx = pcx.fcx.ccx.tcx;
366 let class_fields = ty::lookup_struct_fields(tcx, struct_id);
368 check_struct_pat_fields(pcx, span, fields, class_fields, struct_id,
372 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
377 fields: &[ast::FieldPat],
380 substitutions: &subst::Substs) {
382 let tcx = pcx.fcx.ccx.tcx;
384 // Find the variant that was specified.
385 match tcx.def_map.borrow().find(&pat_id) {
386 Some(&def::DefVariant(found_enum_id, variant_id, _))
387 if found_enum_id == enum_id => {
388 // Get the struct fields from this struct-like enum variant.
389 let class_fields = ty::lookup_struct_fields(tcx, variant_id);
391 check_struct_pat_fields(pcx, span, fields, class_fields,
392 variant_id, substitutions, etc);
394 Some(&def::DefStruct(..)) |
395 Some(&def::DefVariant(..)) |
396 Some(&def::DefTy(..)) => {
397 let name = pprust::path_to_string(path);
398 span_err!(tcx.sess, span, E0028,
399 "mismatched types: expected `{}` but found `{}`",
400 fcx.infcx().ty_to_string(expected), name);
403 tcx.sess.span_bug(span, "resolve didn't write in variant");
408 // Pattern checking is top-down rather than bottom-up so that bindings get
409 // their types immediately.
410 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
412 let tcx = pcx.fcx.ccx.tcx;
415 ast::PatWild | ast::PatWildMulti => {
416 fcx.write_ty(pat.id, expected);
418 ast::PatLit(ref lt) => {
419 check_expr_has_type(fcx, &**lt, expected);
420 fcx.write_ty(pat.id, fcx.expr_ty(&**lt));
422 ast::PatRange(ref begin, ref end) => {
423 check_expr_has_type(fcx, &**begin, expected);
424 check_expr_has_type(fcx, &**end, expected);
426 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**begin));
428 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(&**end));
429 debug!("pat_range beginning type: {:?}", b_ty);
430 debug!("pat_range ending type: {:?}", e_ty);
431 if !require_same_types(
432 tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
433 || "mismatched types in range".to_string())
436 } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
437 span_err!(tcx.sess, begin.span, E0029,
438 "only char and numeric types are allowed in range");
440 match valid_range_bounds(fcx.ccx, &**begin, &**end) {
442 span_err!(tcx.sess, begin.span, E0030,
443 "lower range bound must be less than upper");
446 span_err!(tcx.sess, begin.span, E0031,
447 "mismatched types in range");
452 fcx.write_ty(pat.id, b_ty);
455 ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
456 let const_did = tcx.def_map.borrow().get_copy(&pat.id).def_id();
457 let const_pty = ty::lookup_item_type(tcx, const_did);
458 demand::suptype(fcx, pat.span, expected, const_pty.ty);
459 fcx.write_ty(pat.id, const_pty.ty);
461 ast::PatIdent(bm, ref path1, sub) if pat_is_binding(&tcx.def_map, pat) => {
462 let typ = fcx.local_ty(pat.span, pat.id);
465 ast::BindByRef(mutbl) => {
466 // if the binding is like
467 // ref x | ref const x | ref mut x
468 // then the type of x is &M T where M is the mutability
469 // and T is the expected type
471 fcx.infcx().next_region_var(
472 infer::PatternRegion(pat.span));
473 let mt = ty::mt {ty: expected, mutbl: mutbl};
474 let region_ty = ty::mk_rptr(tcx, region_var, mt);
475 demand::eqtype(fcx, pat.span, region_ty, typ);
477 // otherwise the type of x is the expected type T
478 ast::BindByValue(_) => {
479 demand::eqtype(fcx, pat.span, expected, typ);
483 let canon_id = *pcx.map.get(&path1.node);
484 if canon_id != pat.id {
485 let ct = fcx.local_ty(pat.span, canon_id);
486 demand::eqtype(fcx, pat.span, ct, typ);
488 fcx.write_ty(pat.id, typ);
490 debug!("(checking match) writing type {} (expected {}) for pat id {}",
491 ppaux::ty_to_string(tcx, typ),
492 ppaux::ty_to_string(tcx, expected),
496 Some(ref p) => check_pat(pcx, &**p, expected),
500 // it's not a binding, it's an enum in disguise:
501 ast::PatIdent(_, ref path1, _) => {
502 let path = ast_util::ident_to_path(path1.span,path1.node);
503 check_pat_variant(pcx, pat, &path, &Some(Vec::new()), expected);
505 ast::PatEnum(ref path, ref subpats) => {
506 check_pat_variant(pcx, pat, path, subpats, expected);
508 ast::PatStruct(ref path, ref fields, etc) => {
509 // Grab the class data that we care about.
510 let structure = structure_of(fcx, pat.span, expected);
511 let mut error_happened = false;
513 ty::ty_struct(cid, ref substs) => {
514 // Verify that the pattern named the right structure.
515 let item_did = tcx.def_map.borrow().get(&pat.id).def_id();
516 match ty::ty_to_def_id(ty::lookup_item_type(tcx, item_did).ty) {
517 Some(struct_did) if struct_did != cid => {
518 span_err!(tcx.sess, path.span, E0032,
519 "`{}` does not name the structure `{}`",
520 pprust::path_to_string(path),
521 fcx.infcx().ty_to_string(expected));
527 format!("This shouldn't happen: failed to lookup structure. \
528 item_did = {}", item_did).as_slice())
532 check_struct_pat(pcx, pat.id, pat.span, expected, path,
533 fields.as_slice(), etc, cid, substs);
535 ty::ty_enum(eid, ref substs) => {
536 check_struct_like_enum_variant_pat(pcx,
547 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
548 fcx.infcx().type_error_message_str_with_expected(pat.span,
550 expected.map_or("".to_string(),
552 format!("mismatched types: expected \
553 `{}` but found {}", e, actual)
556 "a structure pattern".to_string(),
558 match tcx.def_map.borrow().find(&pat.id) {
560 check_struct_pat(pcx,
568 &subst::Substs::empty());
571 tcx.sess.span_bug(pat.span,
572 "whoops, looks like resolve didn't \
573 write a def in here")
576 error_happened = true;
580 // Finally, write in the type.
582 fcx.write_error(pat.id);
584 fcx.write_ty(pat.id, expected);
587 ast::PatTup(ref elts) => {
588 let s = structure_of(fcx, pat.span, expected);
589 let e_count = elts.len();
591 ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
592 for (i, elt) in elts.iter().enumerate() {
593 check_pat(pcx, &**elt, *ex_elts.get(i));
595 fcx.write_ty(pat.id, expected);
598 for elt in elts.iter() {
599 check_pat(pcx, &**elt, ty::mk_err());
601 // use terr_tuple_size if both types are tuples
602 let type_error = match *s {
603 ty::ty_tup(ref ex_elts) => {
604 ty::terr_tuple_size(ty::expected_found {
605 expected: ex_elts.len(),
609 _ => ty::terr_mismatch
611 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
612 fcx.infcx().type_error_message_str_with_expected(pat.span,
615 expected.map_or("".to_string(), |e| {
616 format!("mismatched types: expected `{}` \
617 but found {}", e, actual)
623 fcx.write_error(pat.id);
627 ast::PatBox(ref inner) => {
628 check_pointer_pat(pcx, Send, &**inner, pat.id, pat.span, expected);
630 ast::PatRegion(ref inner) => {
631 check_pointer_pat(pcx, Borrowed, &**inner, pat.id, pat.span, expected);
633 ast::PatVec(ref before, slice, ref after) => {
634 let default_region_var =
635 fcx.infcx().next_region_var(
636 infer::PatternRegion(pat.span));
638 let check_err = |found: String| {
639 for &elt in before.iter() {
640 check_pat(pcx, &*elt, ty::mk_err());
642 for elt in slice.iter() {
643 check_pat(pcx, &**elt, ty::mk_err());
645 for elt in after.iter() {
646 check_pat(pcx, &**elt, ty::mk_err());
648 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
649 fcx.infcx().type_error_message_str_with_expected(
652 expected.map_or("".to_string(),
654 format!("mismatched types: expected `{}` but found {}",
661 fcx.write_error(pat.id);
664 let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
667 ty::ty_vec(mt, Some(fixed)) =>
668 (mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
669 ty::ty_uniq(t) => match ty::get(t).sty {
670 ty::ty_vec(mt, None) => {
671 fcx.type_error_message(pat.span,
673 "unique vector patterns are no \
674 longer supported".to_string()
678 (mt.ty, default_region_var, ast::MutImmutable, None)
681 check_err("a vector pattern".to_string());
685 ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
686 ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
688 check_err("a vector pattern".to_string());
693 check_err("a vector pattern".to_string());
698 let min_len = before.len() + after.len();
699 fixed.and_then(|count| match slice {
700 Some(_) if count < min_len =>
701 Some(format!("a fixed vector pattern of size at least {}", min_len)),
703 None if count != min_len =>
704 Some(format!("a fixed vector pattern of size {}", min_len)),
709 for elt in before.iter() {
710 check_pat(pcx, &**elt, elt_type);
713 Some(ref slice_pat) => {
714 let slice_ty = ty::mk_slice(tcx,
716 ty::mt {ty: elt_type, mutbl: mutbl});
717 check_pat(pcx, &**slice_pat, slice_ty);
721 for elt in after.iter() {
722 check_pat(pcx, &**elt, elt_type);
724 fcx.write_ty(pat.id, expected);
727 ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
731 // Helper function to check gc, box and & patterns
732 fn check_pointer_pat(pcx: &pat_ctxt,
733 pointer_kind: PointerKind,
739 let tcx = fcx.ccx.tcx;
740 let check_inner: |ty::t| = |e_inner| {
741 match ty::get(e_inner).sty {
742 ty::ty_trait(_) if pat_is_binding(&tcx.def_map, inner) => {
743 // This is "x = SomeTrait" being reduced from
744 // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
745 check_pat(pcx, inner, ty::mk_err());
746 span_err!(tcx.sess, span, E0033,
747 "type `{}` cannot be dereferenced",
748 fcx.infcx().ty_to_string(expected));
749 fcx.write_error(pat_id);
752 check_pat(pcx, inner, e_inner);
753 fcx.write_ty(pat_id, expected);
758 match *structure_of(fcx, span, expected) {
759 ty::ty_uniq(e_inner) if pointer_kind == Send => {
760 check_inner(e_inner);
762 ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
763 check_inner(e_inner.ty);
766 check_pat(pcx, inner, ty::mk_err());
767 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
768 fcx.infcx().type_error_message_str_with_expected(
771 expected.map_or("".to_string(), |e| {
772 format!("mismatched types: expected `{}` but found {}",
777 format!("{} pattern", match pointer_kind {
779 Borrowed => "an `&`-pointer",
782 fcx.write_error(pat_id);
787 #[deriving(PartialEq)]
788 pub enum PointerKind {