about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSeo Sanghyeon <sanxiyn@gmail.com>2013-02-20 01:43:15 +0900
committerSeo Sanghyeon <sanxiyn@gmail.com>2013-02-20 02:44:02 +0900
commita29023e9b2b42e94d77404496e72d0132aa44a6b (patch)
tree82078f056e42128792c63b6dcdc89051d13e138e
parent67ee95e943163d8d3dad439bfb0ce94e3e9c9aa4 (diff)
downloadrust-a29023e9b2b42e94d77404496e72d0132aa44a6b.tar.gz
rust-a29023e9b2b42e94d77404496e72d0132aa44a6b.zip
Check type when struct is matched against enum-like pattern
Previously check always succeeded because struct type was derived from
the matched expression, not the matched pattern.
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/librustc/middle/typeck/check/_match.rs13
-rw-r--r--src/test/compile-fail/match-struct.rs11
3 files changed, 23 insertions, 3 deletions
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index c15010d7b7b..828db3b6a93 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 bd099923f2b..4cbefba31b1 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.
@@ -125,8 +125,17 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
             kind_name = "variant";
         }
         ty::ty_struct(struct_def_id, ref expected_substs) => {
+            // Lookup the struct ctor def id
+            let s_def = lookup_def(pcx.fcx, pat.span, pat.id);
+            let s_def_id = ast_util::def_id_of_def(s_def);
+
             // Assign the pattern the type of the struct.
-            let struct_tpt = ty::lookup_item_type(tcx, struct_def_id);
+            let ctor_tpt = ty::lookup_item_type(tcx, s_def_id);
+            let struct_tpt = if ty::is_fn_ty(ctor_tpt.ty) {
+                {ty: ty::ty_fn_ret(ctor_tpt.ty), ..ctor_tpt}
+            } else {
+                ctor_tpt
+            };
             instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id,
                              pcx.block_region);
 
diff --git a/src/test/compile-fail/match-struct.rs b/src/test/compile-fail/match-struct.rs
new file mode 100644
index 00000000000..fa406aa278e
--- /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(_) => (),
+        _ => ()
+    }
+}