diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c15010d7b7b24..828db3b6a9396 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2823,7 +2823,7 @@ pub pure fn ty_fn_ret(fty: t) -> t { } } -fn is_fn_ty(fty: t) -> bool { +pub fn is_fn_ty(fty: t) -> bool { match get(fty).sty { ty_bare_fn(_) => true, ty_closure(_) => true, diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index bd099923f2bdb..bffa1611478dc 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -92,7 +92,7 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, match structure_of(pcx.fcx, pat.span, expected) { ty::ty_enum(_, ref expected_substs) => { // Lookup the enum and variant def ids: - let v_def = lookup_def(pcx.fcx, path.span, pat.id); + let v_def = lookup_def(pcx.fcx, pat.span, pat.id); let v_def_ids = ast_util::variant_def_ids(v_def); // Assign the pattern the type of the *enum*, not the variant. @@ -130,10 +130,49 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id, pcx.block_region); - // Check that the type of the value being matched is a subtype of - // the type of the pattern. - let pat_ty = fcx.node_ty(pat.id); - demand::suptype(fcx, pat.span, pat_ty, expected); + let s_tcx = pcx.fcx.ccx.tcx; + + // Check to ensure that the tuple is the one specified. + match s_tcx.def_map.find(&pat.id) { + Some(ast::def_struct(supplied_def_id)) + if supplied_def_id == struct_def_id => { + // OK + } + Some(ast::def_struct(*)) if subpats != None => { + let class_fields = ty::lookup_struct_fields(tcx, + struct_def_id); + for class_fields.eachi |i, class_field| { + let field_type = ty::lookup_field_type(tcx, struct_def_id, + class_field.id, + expected_substs); + match /*bad*/copy subpats { + Some(pats) => { + check_pat(pcx, pats[i], field_type); + } + _ => { + let name = pprust::path_to_str(path, tcx.sess.intr()); + tcx.sess.span_err(pat.span, + fmt!("mismatched types: expected \ + `%s` but found `%s`", + pcx.fcx.infcx().ty_to_str(expected), + name)); // unreachable? + } + } + } + } + Some(ast::def_struct(*)) | Some(ast::def_variant(*)) => { + let name = pprust::path_to_str(path, tcx.sess.intr()); + tcx.sess.span_err(pat.span, + fmt!("mismatched types: expected `%s` \ + but found `%s`", + pcx.fcx.infcx().ty_to_str(expected), + name)); + } + _ => { + s_tcx.sess.span_bug(pat.span, ~"resolve didn't write in \ + class"); + } + } // Get the expected types of the arguments. let class_fields = ty::struct_fields( diff --git a/src/test/compile-fail/match-struct.rs b/src/test/compile-fail/match-struct.rs new file mode 100644 index 0000000000000..fa406aa278e81 --- /dev/null +++ b/src/test/compile-fail/match-struct.rs @@ -0,0 +1,11 @@ +// error-pattern: mismatched types + +struct S { a: int } +enum E { C(int) } + +fn main() { + match S { a: 1 } { + C(_) => (), + _ => () + } +}