about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2013-05-02 15:38:19 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2013-05-03 13:03:53 -0700
commit13df2ea69c332d7a20c7ab394020430a09dad507 (patch)
treeb22cc70abd3fa39f64e09fffffbc362a88db0d0c
parent4332f8188b5dca743dfe2913b3f50a7a693ee3ef (diff)
downloadrust-13df2ea69c332d7a20c7ab394020430a09dad507.tar.gz
rust-13df2ea69c332d7a20c7ab394020430a09dad507.zip
rustc: Handle struct patterns where the expected type is an enum
Previously, rustc would ICE if you matched on an enum-typed thing
with a structure pattern. Error out correctly.
-rw-r--r--src/librustc/middle/typeck/check/_match.rs78
-rw-r--r--src/libsyntax/ast_util.rs6
-rw-r--r--src/test/compile-fail/issue-5358-1.rs18
-rw-r--r--src/test/compile-fail/issue-5358.rs17
4 files changed, 85 insertions, 34 deletions
diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs
index de384d02dc3..3937e54853e 100644
--- a/src/librustc/middle/typeck/check/_match.rs
+++ b/src/librustc/middle/typeck/check/_match.rs
@@ -114,37 +114,53 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path,
         ty::ty_enum(_, ref expected_substs) => {
             // Lookup the enum and variant def ids:
             let v_def = lookup_def(pcx.fcx, pat.span, pat.id);
-            let (enm, var) = ast_util::variant_def_ids(v_def);
-
-            // Assign the pattern the type of the *enum*, not the variant.
-            let enum_tpt = ty::lookup_item_type(tcx, enm);
-            instantiate_path(pcx.fcx, path, enum_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::subtype(fcx, pat.span, expected, pat_ty);
-
-            // Get the expected types of the arguments.
-            arg_types = {
-                let vinfo =
-                    ty::enum_variant_with_id(tcx, enm, var);
-                let var_tpt = ty::lookup_item_type(tcx, var);
-                vinfo.args.map(|t| {
-                    if var_tpt.generics.type_param_defs.len() ==
-                        expected_substs.tps.len()
-                    {
-                        ty::subst(tcx, expected_substs, *t)
-                    }
-                    else {
-                        *t // In this case, an error was already signaled
-                           // anyway
-                    }
-                })
-            };
-
-            kind_name = "variant";
+            match ast_util::variant_def_ids(v_def) {
+                Some((enm, var)) => {
+                    // Assign the pattern the type of the *enum*, not the variant.
+                    let enum_tpt = ty::lookup_item_type(tcx, enm);
+                    instantiate_path(pcx.fcx, path, enum_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::subtype(fcx, pat.span, expected, pat_ty);
+                    
+                    // Get the expected types of the arguments.
+                    arg_types = {
+                        let vinfo =
+                            ty::enum_variant_with_id(tcx, enm, var);
+                        let var_tpt = ty::lookup_item_type(tcx, var);
+                        vinfo.args.map(|t| {
+                            if var_tpt.generics.type_param_defs.len() ==
+                                expected_substs.tps.len()
+                            {
+                                ty::subst(tcx, expected_substs, *t)
+                            }
+                            else {
+                                *t // In this case, an error was already signaled
+                                    // anyway
+                            }
+                        })
+                    };
+                    
+                    kind_name = "variant";
+                }
+                None => {
+                    let resolved_expected =
+                        fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected));
+                    fcx.infcx().type_error_message_str(pat.span,
+                                                       |actual| {
+                                                           fmt!("mismatched types: expected `%s` but found %s",
+                                                                resolved_expected, actual)},
+                                                       ~"a structure pattern",
+                                                       None);
+                    fcx.write_error(pat.id);
+                    kind_name = "[error]";
+                    arg_types = (copy subpats).get_or_default(~[]).map(|_|
+                                                                       ty::mk_err());
+                }
+            }
         }
         ty::ty_struct(struct_def_id, ref expected_substs) => {
             // Lookup the struct ctor def id
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 47ef7227842..10350413f2d 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -41,12 +41,12 @@ pub fn stmt_id(s: &stmt) -> node_id {
     }
 }
 
-pub fn variant_def_ids(d: def) -> (def_id, def_id) {
+pub fn variant_def_ids(d: def) -> Option<(def_id, def_id)> {
     match d {
       def_variant(enum_id, var_id) => {
-        return (enum_id, var_id);
+          Some((enum_id, var_id))
       }
-      _ => fail!(~"non-variant in variant_def_ids")
+      _ => None
     }
 }
 
diff --git a/src/test/compile-fail/issue-5358-1.rs b/src/test/compile-fail/issue-5358-1.rs
new file mode 100644
index 00000000000..0b6e2fb0ff5
--- /dev/null
+++ b/src/test/compile-fail/issue-5358-1.rs
@@ -0,0 +1,18 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S(Either<uint, uint>);
+
+fn main() {
+    match S(Left(5)) {
+        Right(_) => {}  //~ ERROR mismatched types: expected `S` but found `core::either::Either
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/issue-5358.rs b/src/test/compile-fail/issue-5358.rs
new file mode 100644
index 00000000000..7d11a127f9a
--- /dev/null
+++ b/src/test/compile-fail/issue-5358.rs
@@ -0,0 +1,17 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S(Either<uint, uint>);
+
+fn main() {
+    match *S(Left(5)) {
+      S(_) => {}  //~ ERROR mismatched types: expected `core::either::Either<uint,uint>` but found a structure pattern
+    }
+}