about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2011-05-27 17:01:08 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2011-05-27 17:42:09 -0700
commitb6e0c5829f5bb87b9a3f0f74b1d98f6ea4cc8cef (patch)
tree73a1da2f5f47baa70997b007cf7f3a00de3cc170 /src
parent0c5a55f2755138a6ddd2fbdfc7b11a4117409c5e (diff)
downloadrust-b6e0c5829f5bb87b9a3f0f74b1d98f6ea4cc8cef.tar.gz
rust-b6e0c5829f5bb87b9a3f0f74b1d98f6ea4cc8cef.zip
Check the declaration type in a for loop against the sequence type
Changed the typechecker to correctly typecheck the declared variable
type in a for or for-each loop against the vector element type (for
a for loop) or the iterator type (for a for-each loop). Added a
test case.
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/typeck.rs54
-rw-r--r--src/test/compile-fail/for-loop-decl.rs23
2 files changed, 62 insertions, 15 deletions
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 635a9b5b404..0147806efc3 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -1872,6 +1872,22 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
         check_call_or_bind(scx, f, args_opt_0);
     }
 
+    // A generic function for checking for or for-each loops
+    fn check_for_or_for_each(&@stmt_ctxt scx, &@ast::decl decl,
+                             &ty::t element_ty, &ast::block body,
+                             uint node_id) {
+        check_decl_local(scx.fcx, decl);
+        check_block(scx, body);
+
+        // Unify type of decl with element type of the seq
+        demand::simple(scx, decl.span, ty::decl_local_ty(scx.fcx.ccx.tcx,
+                                                         decl),
+                       element_ty);
+        
+        auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
+        write::ty_only_fixup(scx, node_id, typ);
+    }
+
     alt (expr.node) {
         case (ast::expr_lit(?lit, ?a)) {
             auto typ = check_lit(scx.fcx.ccx, lit);
@@ -2000,8 +2016,7 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
                 case (none[@ast::expr]) {
                     auto nil = ty::mk_nil(scx.fcx.ccx.tcx);
                     if (!are_compatible(scx, scx.fcx.ret_ty, nil)) {
-                        // TODO: span_err
-                        scx.fcx.ccx.tcx.sess.span_err(expr.span,
+                         scx.fcx.ccx.tcx.sess.span_err(expr.span,
                             "put; in iterator yielding non-nil");
                     }
 
@@ -2159,24 +2174,33 @@ fn check_expr(&@stmt_ctxt scx, &@ast::expr expr) {
         }
 
         case (ast::expr_for(?decl, ?seq, ?body, ?a)) {
-            check_decl_local(scx.fcx, decl);
             check_expr(scx, seq);
-            check_block(scx, body);
-
-            // FIXME: enforce that the type of the decl is the element type
-            // of the seq.
-
-            auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
-            write::ty_only_fixup(scx, a.id, typ);
+            alt (struct (scx.fcx.ccx.tcx,
+                         expr_ty(scx.fcx.ccx.tcx, seq))) {
+                // FIXME: I include the check_for_or_each call in 
+                // each case because of a bug in typestate;
+                // once that bug is fixed, the call can be moved
+                // out of the alt expression
+                case (ty::ty_vec(?vec_elt_ty)) {
+                    auto elt_ty = vec_elt_ty.ty;
+                    check_for_or_for_each(scx, decl, elt_ty, body, a.id);
+                }
+                case (ty::ty_str) {
+                    auto elt_ty = ty::mk_mach(scx.fcx.ccx.tcx, 
+                                         util::common::ty_u8);
+                    check_for_or_for_each(scx, decl, elt_ty, body, a.id);
+                }
+                case (_) {
+                    scx.fcx.ccx.tcx.sess.span_err(expr.span,
+                      "type of for loop iterator is not a vector or string");
+                }
+            }
         }
 
         case (ast::expr_for_each(?decl, ?seq, ?body, ?a)) {
-            check_decl_local(scx.fcx, decl);
             check_expr(scx, seq);
-            check_block(scx, body);
-
-            auto typ = ty::mk_nil(scx.fcx.ccx.tcx);
-            write::ty_only_fixup(scx, a.id, typ);
+            check_for_or_for_each(scx, decl, expr_ty(scx.fcx.ccx.tcx, seq),
+                                  body, a.id);
         }
 
         case (ast::expr_while(?cond, ?body, ?a)) {
diff --git a/src/test/compile-fail/for-loop-decl.rs b/src/test/compile-fail/for-loop-decl.rs
new file mode 100644
index 00000000000..00da58e1745
--- /dev/null
+++ b/src/test/compile-fail/for-loop-decl.rs
@@ -0,0 +1,23 @@
+// error-pattern: mismatched types
+use std;
+import std::map::hashmap;
+import std::bitv;
+
+type fn_info = rec(hashmap[uint, var_info] vars);
+type var_info = rec(uint a, uint b);
+
+fn bitv_to_str(fn_info enclosing, bitv::t v) -> str {
+  auto s = "";
+
+  // error is that the value type in the hash map is var_info, not a tuple
+  for each (@tup(uint, tup(uint, uint)) p in enclosing.vars.items()) {
+    if (bitv::get(v, p._1._0)) {
+      s += "foo"; // " " + p._1._1 + " " + "[" + p._0 + "]";
+    }
+  }
+  ret s;
+}
+
+fn main() {
+  log "OK";
+}
\ No newline at end of file