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)]
13 use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
15 use middle::typeck::check::demand;
16 use middle::typeck::check::{check_expr, check_expr_has_type, FnCtxt};
17 use middle::typeck::check::{instantiate_path, lookup_def};
18 use middle::typeck::check::{structure_of, valid_range_bounds};
19 use middle::typeck::infer;
20 use middle::typeck::require_same_types;
22 use collections::{HashMap, HashSet};
25 use syntax::parse::token;
26 use syntax::codemap::Span;
27 use syntax::print::pprust;
29 pub fn check_match(fcx: &FnCtxt,
33 let tcx = fcx.ccx.tcx;
35 let discrim_ty = fcx.infcx().next_ty_var();
36 check_expr_has_type(fcx, discrim, discrim_ty);
38 // Typecheck the patterns first, so that we get types for all the
40 for arm in arms.iter() {
41 let mut pcx = pat_ctxt {
43 map: pat_id_map(&tcx.def_map, *arm.pats.get(0)),
46 for p in arm.pats.iter() { check_pat(&mut pcx, *p, discrim_ty);}
49 // The result of the match is the common supertype of all the
50 // arms. Start out the value as bottom, since it's the, well,
51 // bottom the type lattice, and we'll be moving up the lattice as
52 // we process each arm. (Note that any match with 0 arms is matching
53 // on any empty type and is therefore unreachable; should the flow
54 // of execution reach it, we will fail, so bottom is an appropriate
56 let mut result_ty = ty::mk_bot();
58 // Now typecheck the blocks.
59 let mut saw_err = ty::type_is_error(discrim_ty);
60 for arm in arms.iter() {
61 let mut guard_err = false;
62 let mut guard_bot = false;
65 check_expr_has_type(fcx, e, ty::mk_bool());
66 let e_ty = fcx.expr_ty(e);
67 if ty::type_is_error(e_ty) {
70 else if ty::type_is_bot(e_ty) {
76 check_expr(fcx, arm.body);
77 let bty = fcx.node_ty(arm.body.id);
78 saw_err = saw_err || ty::type_is_error(bty);
80 fcx.write_error(arm.body.id);
84 fcx.write_bot(arm.body.id);
88 infer::common_supertype(
90 infer::MatchExpression(expr.span),
91 true, // result_ty is "expected" here
97 result_ty = ty::mk_err();
98 } else if ty::type_is_bot(discrim_ty) {
99 result_ty = ty::mk_bot();
102 fcx.write_ty(expr.id, result_ty);
105 pub struct pat_ctxt<'a> {
106 pub fcx: &'a FnCtxt<'a>,
110 pub fn check_pat_variant(pcx: &pat_ctxt, pat: &ast::Pat, path: &ast::Path,
111 subpats: &Option<Vec<@ast::Pat>>, expected: ty::t) {
113 // Typecheck the path.
115 let tcx = pcx.fcx.ccx.tcx;
117 let arg_types: Vec<ty::t> ;
120 // structure_of requires type variables to be resolved.
121 // So when we pass in <expected>, it's an error if it
122 // contains type variables.
124 // Check to see whether this is an enum or a struct.
125 match *structure_of(pcx.fcx, pat.span, expected) {
126 ty::ty_enum(_, ref expected_substs) => {
127 // Lookup the enum and variant def ids:
128 let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
129 match ast_util::variant_def_ids(v_def) {
130 Some((enm, var)) => {
131 // Assign the pattern the type of the *enum*, not the variant.
132 let enum_tpt = ty::lookup_item_type(tcx, enm);
133 instantiate_path(pcx.fcx,
140 // check that the type of the value being matched is a subtype
141 // of the type of the pattern:
142 let pat_ty = fcx.node_ty(pat.id);
143 demand::subtype(fcx, pat.span, expected, pat_ty);
145 // Get the expected types of the arguments.
148 ty::enum_variant_with_id(tcx, enm, var);
149 let var_tpt = ty::lookup_item_type(tcx, var);
150 vinfo.args.iter().map(|t| {
151 if var_tpt.generics.type_param_defs().len() ==
152 expected_substs.tps.len()
154 ty::subst(tcx, expected_substs, *t)
157 *t // In this case, an error was already signaled
163 kind_name = "variant";
166 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
167 fcx.infcx().type_error_message_str_with_expected(pat.span,
169 expected.map_or("".to_string(), |e| {
170 format!("mismatched types: expected `{}` but found {}",
174 "a structure pattern".to_string(),
176 fcx.write_error(pat.id);
177 kind_name = "[error]";
178 arg_types = subpats.clone()
181 .map(|_| ty::mk_err())
186 ty::ty_struct(struct_def_id, ref expected_substs) => {
187 // Lookup the struct ctor def id
188 let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
189 let s_def_id = ast_util::def_id_of_def(s_def);
191 // Assign the pattern the type of the struct.
192 let ctor_tpt = ty::lookup_item_type(tcx, s_def_id);
193 let struct_tpt = if ty::is_fn_ty(ctor_tpt.ty) {
194 ty::ty_param_bounds_and_ty {ty: ty::ty_fn_ret(ctor_tpt.ty),
199 instantiate_path(pcx.fcx,
206 // Check that the type of the value being matched is a subtype of
207 // the type of the pattern.
208 let pat_ty = fcx.node_ty(pat.id);
209 demand::subtype(fcx, pat.span, expected, pat_ty);
211 // Get the expected types of the arguments.
212 let class_fields = ty::struct_fields(
213 tcx, struct_def_id, expected_substs);
214 arg_types = class_fields.iter().map(|field| field.mt.ty).collect();
216 kind_name = "structure";
219 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
220 fcx.infcx().type_error_message_str_with_expected(pat.span,
222 expected.map_or("".to_string(),
224 format!("mismatched types: expected `{}` but found {}",
229 "an enum or structure pattern".to_string(),
231 fcx.write_error(pat.id);
232 kind_name = "[error]";
233 arg_types = subpats.clone()
236 .map(|_| ty::mk_err())
241 let arg_len = arg_types.len();
243 // Count the number of subpatterns.
246 None => subpats_len = arg_len,
247 Some(ref subpats) => subpats_len = subpats.len()
250 let mut error_happened = false;
254 if arg_len != subpats_len {
255 let s = format!("this pattern has \
256 {npat, plural, =1{# field} other{# fields}}, \
257 but the corresponding {kind} has \
258 {narg, plural, =1{# field} other{# fields}}",
262 tcx.sess.span_err(pat.span, s.as_slice());
263 error_happened = true;
267 for pats in subpats.iter() {
268 for (subpat, arg_ty) in pats.iter().zip(arg_types.iter()) {
269 check_pat(pcx, *subpat, *arg_ty);
273 } else if subpats_len > 0 {
274 tcx.sess.span_err(pat.span,
275 format!("this pattern has \
276 {npat, plural, =1{# field} other{# fields}}, \
277 but the corresponding {kind} has no fields",
279 kind = kind_name).as_slice());
280 error_happened = true;
284 for pats in subpats.iter() {
285 for pat in pats.iter() {
286 check_pat(pcx, *pat, ty::mk_err());
292 /// `path` is the AST path item naming the type of this struct.
293 /// `fields` is the field patterns of the struct pattern.
294 /// `class_fields` describes the type of each field of the struct.
295 /// `class_id` is the ID of the struct.
296 /// `substitutions` are the type substitutions applied to this struct type
297 /// (e.g. K,V in HashMap<K,V>).
298 /// `etc` is true if the pattern said '...' and false otherwise.
299 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: &ty::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 let name = pprust::path_to_str(path);
337 // Check the pattern anyway, so that attempts to look
338 // up its type won't fail
339 check_pat(pcx, field.pat, ty::mk_err());
340 tcx.sess.span_err(span,
341 format!("struct `{}` does not have a field named `{}`",
343 token::get_ident(field.ident)).as_slice());
348 // Report an error if not all the fields were specified.
350 for (i, field) in class_fields.iter().enumerate() {
351 if found_fields.contains(&i) {
357 format!("pattern does not mention field `{}`",
358 token::get_name(field.name)).as_slice());
363 pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::NodeId, span: Span,
364 expected: ty::t, path: &ast::Path,
365 fields: &[ast::FieldPat], etc: bool,
366 struct_id: ast::DefId,
367 substitutions: &ty::substs) {
369 let tcx = pcx.fcx.ccx.tcx;
371 let class_fields = ty::lookup_struct_fields(tcx, struct_id);
373 // Check to ensure that the struct is the one specified.
374 match tcx.def_map.borrow().find(&pat_id) {
375 Some(&ast::DefStruct(supplied_def_id))
376 if supplied_def_id == struct_id => {
379 Some(&ast::DefStruct(..)) | Some(&ast::DefVariant(..)) => {
380 let name = pprust::path_to_str(path);
383 format!("mismatched types: expected `{}` but found \
385 fcx.infcx().ty_to_str(expected),
389 tcx.sess.span_bug(span, "resolve didn't write in struct ID");
393 check_struct_pat_fields(pcx, span, path, fields, class_fields, struct_id,
397 pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt,
402 fields: &[ast::FieldPat],
405 substitutions: &ty::substs) {
407 let tcx = pcx.fcx.ccx.tcx;
409 // Find the variant that was specified.
410 match tcx.def_map.borrow().find(&pat_id) {
411 Some(&ast::DefVariant(found_enum_id, variant_id, _))
412 if found_enum_id == enum_id => {
413 // Get the struct fields from this struct-like enum variant.
414 let class_fields = ty::lookup_struct_fields(tcx, variant_id);
416 check_struct_pat_fields(pcx, span, path, fields, class_fields,
417 variant_id, substitutions, etc);
419 Some(&ast::DefStruct(..)) | Some(&ast::DefVariant(..)) => {
420 let name = pprust::path_to_str(path);
421 tcx.sess.span_err(span,
422 format!("mismatched types: expected `{}` but \
424 fcx.infcx().ty_to_str(expected),
428 tcx.sess.span_bug(span, "resolve didn't write in variant");
433 // Pattern checking is top-down rather than bottom-up so that bindings get
434 // their types immediately.
435 pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
437 let tcx = pcx.fcx.ccx.tcx;
440 ast::PatWild | ast::PatWildMulti => {
441 fcx.write_ty(pat.id, expected);
444 check_expr_has_type(fcx, lt, expected);
445 fcx.write_ty(pat.id, fcx.expr_ty(lt));
447 ast::PatRange(begin, end) => {
448 check_expr_has_type(fcx, begin, expected);
449 check_expr_has_type(fcx, end, expected);
451 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(begin));
453 fcx.infcx().resolve_type_vars_if_possible(fcx.expr_ty(end));
454 debug!("pat_range beginning type: {:?}", b_ty);
455 debug!("pat_range ending type: {:?}", e_ty);
456 if !require_same_types(
457 tcx, Some(fcx.infcx()), false, pat.span, b_ty, e_ty,
458 || "mismatched types in range".to_string())
461 } else if !ty::type_is_numeric(b_ty) && !ty::type_is_char(b_ty) {
462 tcx.sess.span_err(pat.span, "non-numeric type used 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 = ast_util::def_id_of_def(tcx.def_map.borrow()
482 let const_tpt = ty::lookup_item_type(tcx, const_did);
483 demand::suptype(fcx, pat.span, expected, const_tpt.ty);
484 fcx.write_ty(pat.id, const_tpt.ty);
486 ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
487 let typ = fcx.local_ty(pat.span, pat.id);
490 ast::BindByRef(mutbl) => {
491 // if the binding is like
492 // ref x | ref const x | ref mut x
493 // then the type of x is &M T where M is the mutability
494 // and T is the expected type
496 fcx.infcx().next_region_var(
497 infer::PatternRegion(pat.span));
498 let mt = ty::mt {ty: expected, mutbl: mutbl};
499 let region_ty = ty::mk_rptr(tcx, region_var, mt);
500 demand::eqtype(fcx, pat.span, region_ty, typ);
502 // otherwise the type of x is the expected type T
503 ast::BindByValue(_) => {
504 demand::eqtype(fcx, pat.span, expected, typ);
508 let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
509 if canon_id != pat.id {
510 let ct = fcx.local_ty(pat.span, canon_id);
511 demand::eqtype(fcx, pat.span, ct, typ);
513 fcx.write_ty(pat.id, typ);
515 debug!("(checking match) writing type for pat id {}", pat.id);
518 Some(p) => check_pat(pcx, p, expected),
522 ast::PatIdent(_, ref path, _) => {
523 check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
525 ast::PatEnum(ref path, ref subpats) => {
526 check_pat_variant(pcx, pat, path, subpats, expected);
528 ast::PatStruct(ref path, ref fields, etc) => {
529 // Grab the class data that we care about.
530 let structure = structure_of(fcx, pat.span, expected);
531 let mut error_happened = false;
533 ty::ty_struct(cid, ref substs) => {
534 check_struct_pat(pcx, pat.id, pat.span, expected, path,
535 fields.as_slice(), etc, cid, substs);
537 ty::ty_enum(eid, ref substs) => {
538 check_struct_like_enum_variant_pat(pcx,
549 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
550 fcx.infcx().type_error_message_str_with_expected(pat.span,
552 expected.map_or("".to_string(),
554 format!("mismatched types: expected \
555 `{}` but found {}", e, actual)
558 "a structure pattern".to_string(),
560 match tcx.def_map.borrow().find(&pat.id) {
561 Some(&ast::DefStruct(supplied_def_id)) => {
562 check_struct_pat(pcx,
573 regions: ty::ErasedRegions,
576 _ => () // Error, but we're already in an error case
578 error_happened = true;
582 // Finally, write in the type.
584 fcx.write_error(pat.id);
586 fcx.write_ty(pat.id, expected);
589 ast::PatTup(ref elts) => {
590 let s = structure_of(fcx, pat.span, expected);
591 let e_count = elts.len();
593 ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => {
594 for (i, elt) in elts.iter().enumerate() {
595 check_pat(pcx, *elt, *ex_elts.get(i));
597 fcx.write_ty(pat.id, expected);
600 for elt in elts.iter() {
601 check_pat(pcx, *elt, ty::mk_err());
603 // use terr_tuple_size if both types are tuples
604 let type_error = match *s {
605 ty::ty_tup(ref ex_elts) => {
606 ty::terr_tuple_size(ty::expected_found {
607 expected: ex_elts.len(),
611 _ => ty::terr_mismatch
613 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
614 fcx.infcx().type_error_message_str_with_expected(pat.span,
617 expected.map_or("".to_string(), |e| {
618 format!("mismatched types: expected `{}` \
619 but found {}", e, actual)
625 fcx.write_error(pat.id);
629 ast::PatUniq(inner) => {
630 check_pointer_pat(pcx, Send, inner, pat.id, pat.span, expected);
632 ast::PatRegion(inner) => {
633 check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected);
635 ast::PatVec(ref before, slice, ref after) => {
636 let default_region_var =
637 fcx.infcx().next_region_var(
638 infer::PatternRegion(pat.span));
641 for &elt in before.iter() {
642 check_pat(pcx, elt, ty::mk_err());
644 for &elt in slice.iter() {
645 check_pat(pcx, elt, ty::mk_err());
647 for &elt in after.iter() {
648 check_pat(pcx, elt, ty::mk_err());
650 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
651 fcx.infcx().type_error_message_str_with_expected(
654 expected.map_or("".to_string(),
656 format!("mismatched types: expected `{}` but found {}",
661 "a vector pattern".to_string(),
663 fcx.write_error(pat.id);
666 let (elt_type, region_var, mutbl) = match *structure_of(fcx,
669 ty::ty_vec(mt, Some(_)) => (mt.ty, default_region_var, ast::MutImmutable),
670 ty::ty_uniq(t) => match ty::get(t).sty {
671 ty::ty_vec(mt, None) => {
672 fcx.type_error_message(pat.span,
674 "unique vector patterns are no \
675 longer supported".to_string()
679 (mt.ty, default_region_var, ast::MutImmutable)
686 ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
687 ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl),
698 for elt in before.iter() {
699 check_pat(pcx, *elt, elt_type);
703 let slice_ty = ty::mk_slice(tcx,
705 ty::mt {ty: elt_type, mutbl: mutbl});
706 check_pat(pcx, slice_pat, slice_ty);
710 for elt in after.iter() {
711 check_pat(pcx, *elt, elt_type);
713 fcx.write_ty(pat.id, expected);
716 ast::PatMac(_) => tcx.sess.bug("unexpanded macro"),
720 // Helper function to check @, box and & patterns
721 pub fn check_pointer_pat(pcx: &pat_ctxt,
722 pointer_kind: PointerKind,
728 let check_inner: |ty::t| = |e_inner| {
729 check_pat(pcx, inner, e_inner);
730 fcx.write_ty(pat_id, expected);
732 match *structure_of(fcx, span, expected) {
733 ty::ty_uniq(e_inner) if pointer_kind == Send => {
734 check_inner(e_inner);
736 ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => {
737 check_inner(e_inner.ty);
740 check_pat(pcx, inner, ty::mk_err());
741 // See [Note-Type-error-reporting] in middle/typeck/infer/mod.rs
742 fcx.infcx().type_error_message_str_with_expected(
745 expected.map_or("".to_string(), |e| {
746 format!("mismatched types: expected `{}` but found {}",
751 format!("{} pattern", match pointer_kind {
753 Borrowed => "an `&`-pointer",
756 fcx.write_error(pat_id);
762 pub enum PointerKind {