Add a constraint in trans
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.
This commit is contained in:
parent
60d0a9227b
commit
786963d33d
3 changed files with 31 additions and 9 deletions
|
@ -777,22 +777,25 @@ fn GEP_tup_like(cx: &@block_ctxt, t: ty::t, base: ValueRef, ixs: &[int]) ->
|
|||
// 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_structural_ty(cx: @block_ctxt, av: ValueRef, t: ty::t,
|
|||
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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue