]> git.lizzy.rs Git - rust.git/commitdiff
Add a constraint in trans
authorTim Chevalier <chevalier@alum.wellesley.edu>
Fri, 2 Sep 2011 00:25:06 +0000 (17:25 -0700)
committerTim Chevalier <chevalier@alum.wellesley.edu>
Fri, 2 Sep 2011 00:41:10 +0000 (17:41 -0700)
Experimenting with adding typestate constraints in the compiler.
Added a constraint to GEP_tag that says the variant index is in
bounds. Added necessary checks.

src/comp/middle/trans.rs
src/comp/middle/trans_alt.rs
src/comp/middle/trans_common.rs

index 8aafae528206c23b8dc9cb0afde12c8d5c77038e..ef2695fb2ab9461a17fcf579e1cdd5565a7a1e07 100644 (file)
@@ -777,22 +777,25 @@ fn split_type(ccx: &@crate_ctxt, t: ty::t, ixs: &[int], n: uint) ->
 // meaningless, as it will be cast away.
 fn GEP_tag(cx: @block_ctxt, llblobptr: ValueRef, tag_id: &ast::def_id,
            variant_id: &ast::def_id, ty_substs: &[ty::t], ix: uint)
-    -> result {
+    : valid_variant_index(ix, cx, tag_id, variant_id) -> result {
     let variant = ty::tag_variant_with_id(bcx_tcx(cx), tag_id, variant_id);
     // Synthesize a tuple type so that GEP_tup_like() can work its magic.
     // Separately, store the type of the element we're interested in.
 
     let arg_tys = variant.args;
-    let elem_ty = ty::mk_nil(bcx_tcx(cx)); // typestate infelicity
 
-    let i = 0u;
     let true_arg_tys: [ty::t] = [];
     for aty: ty::t in arg_tys {
         let arg_ty = ty::substitute_type_params(bcx_tcx(cx), ty_substs, aty);
         true_arg_tys += [arg_ty];
-        if i == ix { elem_ty = arg_ty; }
-        i += 1u;
     }
+
+    // We know that ix < len(variant.args) -- so
+    // it's safe to do this. (Would be nice to have
+    // typestate guarantee that a dynamic bounds check
+    // error can't happen here, but that's in the future.)
+    let elem_ty = true_arg_tys[ix];
+
     let tup_ty = ty::mk_tup(bcx_tcx(cx), true_arg_tys);
     // Cast the blob pointer to the appropriate type, if we need to (i.e. if
     // the blob pointer isn't dynamically sized).
@@ -1670,8 +1673,10 @@ fn iter_variant(cx: @block_ctxt, a_tup: ValueRef,
         alt ty::struct(ccx.tcx, fn_ty) {
           ty::ty_fn(_, args, _, _, _) {
             let j = 0u;
+            let v_id = variant.id;
             for a: ty::arg in args {
-                let rslt = GEP_tag(cx, a_tup, tid, variant.id, tps, j);
+                check valid_variant_index(j, cx, tid, v_id);
+                let rslt = GEP_tag(cx, a_tup, tid, v_id, tps, j);
                 let llfldp_a = rslt.val;
                 cx = rslt.bcx;
                 let ty_subst = ty::substitute_type_params(ccx.tcx, tps, a.ty);
@@ -5352,10 +5357,12 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
             GEP(bcx, lltagptr, [C_int(0), C_int(1)])
         };
     i = 0u;
+    let t_id = ast_util::local_def(tag_id);
+    let v_id = ast_util::local_def(variant.node.id);
     for va: ast::variant_arg in variant.node.args {
+        check valid_variant_index(i, bcx, t_id, v_id);
         let rslt =
-            GEP_tag(bcx, llblobptr, ast_util::local_def(tag_id),
-                    ast_util::local_def(variant.node.id), ty_param_substs, i);
+            GEP_tag(bcx, llblobptr, t_id, v_id, ty_param_substs, i);
         bcx = rslt.bcx;
         let lldestptr = rslt.val;
         // If this argument to this function is a tag, it'll have come in to
index a4cdb44f5741706a5a240d7b51f2063eb96c432f..9157ea579ad5a7fba1288f8aadc8460c3ef8df6d 100644 (file)
@@ -216,9 +216,12 @@ fn extract_variant_args(bcx: @block_ctxt, pat_id: ast::node_id,
         blobptr = GEP(bcx, tagptr, [C_int(0), C_int(1)]);
     }
     let i = 0u;
+    let vdefs_tg = vdefs.tg;
+    let vdefs_var = vdefs.var;
     while i < size {
+        check valid_variant_index(i, bcx, vdefs_tg, vdefs_var);
         let r =
-            trans::GEP_tag(bcx, blobptr, vdefs.tg, vdefs.var, ty_param_substs,
+            trans::GEP_tag(bcx, blobptr, vdefs_tg, vdefs_var, ty_param_substs,
                            i);
         bcx = r.bcx;
         args += [r.val];
index 5a7bb4faf0720de2da406ea7bddadfb2bca1db63..816bd6550993e063da38672124d2ab21bf68f00d 100644 (file)
@@ -881,6 +881,18 @@ fn C_shape(ccx: &@crate_ctxt, bytes: &[u8]) -> ValueRef {
     ret llvm::LLVMConstPointerCast(llglobal, T_ptr(T_i8()));
 }
 
+
+pure fn valid_variant_index(ix:uint, cx:@block_ctxt, tag_id: &ast::def_id,
+                            variant_id: &ast::def_id) -> bool {
+    // Handwaving: it's ok to pretend this code is referentially
+    // transparent, because the relevant parts of the type context don't
+    // change. (We're not adding new variants during trans.)
+    unchecked {
+      let variant = ty::tag_variant_with_id(bcx_tcx(cx), tag_id, variant_id);
+      ix < vec::len(variant.args)
+    }
+}
+
 //
 // Local Variables:
 // mode: rust