Support type parameters in resources

Some rather dodgy code was added to trans in the process. I'd love to
discuss it with someone who knows more about types during translation.
This commit is contained in:
Marijn Haverbeke 2011-06-30 14:46:17 +02:00
parent 31ec26d46a
commit 86f16b90cd
8 changed files with 163 additions and 65 deletions

View File

@ -1570,6 +1570,13 @@ fn type_to_str_inner(type_names names,
}
}
fn fn_ty_param_tys(TypeRef fn_ty) -> vec[TypeRef] {
auto args = vec::init_elt(0 as TypeRef, llvm::LLVMCountParamTypes(fn_ty));
llvm::LLVMGetParamTypes(fn_ty, vec::buf(args));
ret args;
}
/* Memory-managed interface to target data. */
obj target_data_dtor(TargetDataRef TD) {

View File

@ -257,9 +257,13 @@ fn parse_ty(@pstate st, str_def sd) -> ty::t {
ret ty::mk_obj(st.tcx, methods);
}
case ('r') {
assert (next(st) as char == '[');
auto def = parse_def(st, sd);
auto inner = parse_ty(st, sd);
ret ty::mk_res(st.tcx, def, inner);
let vec[ty::t] params = [];
while (peek(st) as char != ']') { params += [parse_ty(st, sd)]; }
st.pos = st.pos + 1u;
ret ty::mk_res(st.tcx, def, inner, params);
}
case ('X') { ret ty::mk_var(st.tcx, parse_int(st)); }
case ('E') { ret ty::mk_native(st.tcx); }

View File

@ -172,11 +172,13 @@ fn enc_sty(&io::writer w, &@ctxt cx, &ty::sty st) {
}
w.write_char(']');
}
case (ty::ty_res(?def, ?ty)) {
w.write_char('r');
case (ty::ty_res(?def, ?ty, ?tps)) {
w.write_str("r[");
w.write_str(cx.ds(def));
w.write_char('|');
enc_ty(w, cx, ty);
for (ty::t t in tps) { enc_ty(w, cx, t); }
w.write_char(']');
}
case (ty::ty_var(?id)) {
w.write_char('X');

View File

@ -556,7 +556,7 @@ fn expr_root(&ctx cx, @ast::expr ex, bool autoderef) ->
kind=unbox,
outer_t=base_t));
}
case (ty::ty_res(_, ?inner)) {
case (ty::ty_res(_, ?inner, _)) {
vec::push(ds, rec(mut=false,
kind=unbox,
outer_t=base_t));

View File

@ -876,8 +876,9 @@ fn type_of_inner(&@crate_ctxt cx, &span sp, &ty::t t) -> TypeRef {
abs_pair = llvm::LLVMResolveTypeHandle(th.llth);
llty = abs_pair;
}
case (ty::ty_res(_, ?sub)) {
ret T_struct([T_i32(), type_of_inner(cx, sp, sub)]);
case (ty::ty_res(_, ?sub, ?tps)) {
auto sub1 = ty::substitute_type_params(cx.tcx, tps, sub);
ret T_struct([T_i32(), type_of_inner(cx, sp, sub1)]);
}
case (ty::ty_var(_)) {
cx.tcx.sess.span_fatal(sp, "trans::type_of called on ty_var");
@ -1220,9 +1221,10 @@ fn simplify_type(&@crate_ctxt ccx, &ty::t typ) -> ty::t {
ty::mk_imm_box(ccx.tcx,
ty::mk_nil(ccx.tcx))]);
}
case (ty::ty_res(_, ?sub)) {
case (ty::ty_res(_, ?sub, ?tps)) {
auto sub1 = ty::substitute_type_params(ccx.tcx, tps, sub);
ret ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx),
simplify_type(ccx, sub)]);
simplify_type(ccx, sub1)]);
}
case (_) { ret typ; }
}
@ -1716,8 +1718,7 @@ fn get_tydesc(&@block_ctxt cx, &ty::t t, bool escapes,
}
// Otherwise, generate a tydesc if necessary, and return it.
let vec[uint] tps = [];
auto info = get_static_tydesc(cx, t, tps);
auto info = get_static_tydesc(cx, t, []);
static_ti = some[@tydesc_info](info);
ret rslt(cx, info.tydesc);
}
@ -2089,8 +2090,8 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
cx.build.GEP(v0, [C_int(0), C_int(abi::obj_field_box)]);
decr_refcnt_maybe_free(cx, box_cell, v0, t)
}
case (ty::ty_res(?did, ?inner)) {
trans_res_drop(cx, v0, did, inner)
case (ty::ty_res(?did, ?inner, ?tps)) {
trans_res_drop(cx, v0, did, inner, tps)
}
case (ty::ty_fn(_, _, _, _, _)) {
auto box_cell =
@ -2108,9 +2109,11 @@ fn make_drop_glue(&@block_ctxt cx, ValueRef v0, &ty::t t) {
}
fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
ty::t inner_t) -> result {
ty::t inner_t, &vec[ty::t] tps) -> result {
auto ccx = cx.fcx.lcx.ccx;
auto tup_ty = ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t]);
auto inner_t_s = ty::substitute_type_params(ccx.tcx, tps, inner_t);
auto tup_ty = ty::mk_imm_tup(ccx.tcx, [ty::mk_int(ccx.tcx), inner_t_s]);
auto drop_cx = new_sub_block_ctxt(cx, "drop res");
auto next_cx = new_sub_block_ctxt(cx, "next");
@ -2120,6 +2123,8 @@ fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
cx.build.CondBr(null_test, next_cx.llbb, drop_cx.llbb);
cx = drop_cx;
auto val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
cx = val.bcx;
// Find and call the actual destructor.
auto dtor_pair = if (did._0 == ast::local_crate) {
ccx.fn_pairs.get(did._1)
@ -2136,15 +2141,25 @@ fn trans_res_drop(@block_ctxt cx, ValueRef rs, &ast::def_id did,
(cx.build.GEP(dtor_pair, [C_int(0), C_int(abi::fn_field_code)]));
auto dtor_env = cx.build.Load
(cx.build.GEP(dtor_pair, [C_int(0), C_int(abi::fn_field_box)]));
auto val = GEP_tup_like(cx, tup_ty, rs, [0, 1]);
cx = val.bcx;
cx.build.FastCall(dtor_addr, [cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env]
+ cx.fcx.lltydescs + [val.val]);
auto args = [cx.fcx.llretptr, cx.fcx.lltaskptr, dtor_env];
for (ty::t tp in tps) {
let option::t[@tydesc_info] ti = none;
auto td = get_tydesc(cx, tp, false, ti);
args += [td.val];
cx = td.bcx;
}
// Kludge to work around the fact that we know the precise type of the
// value here, but the dtor expects a type that still has opaque pointers
// for type variables.
auto val_llty = lib::llvm::fn_ty_param_tys
(llvm::LLVMGetElementType(llvm::LLVMTypeOf(dtor_addr)))
.(vec::len(args));
auto val_cast = cx.build.BitCast(val.val, val_llty);
cx.build.FastCall(dtor_addr, args + [val_cast]);
cx = drop_slot(cx, val.val, inner_t).bcx;
cx = drop_slot(cx, val.val, inner_t_s).bcx;
cx.build.Store(C_int(0), drop_flag.val);
cx.build.Br(next_cx.llbb);
ret rslt(next_cx, C_nil());
}
@ -2611,13 +2626,15 @@ fn iter_structural_ty_full(&@block_ctxt cx, ValueRef av, ValueRef bv,
i += 1;
}
}
case (ty::ty_res(_, ?inner)) {
case (ty::ty_res(_, ?inner, ?tps)) {
auto inner1 = ty::substitute_type_params(cx.fcx.lcx.ccx.tcx,
tps, inner);
r = GEP_tup_like(r.bcx, t, av, [0, 1]);
auto llfld_a = r.val;
r = GEP_tup_like(r.bcx, t, bv, [0, 1]);
auto llfld_b = r.val;
f(r.bcx, load_if_immediate(r.bcx, llfld_a, inner),
load_if_immediate(r.bcx, llfld_b, inner), inner);
f(r.bcx, load_if_immediate(r.bcx, llfld_a, inner1),
load_if_immediate(r.bcx, llfld_b, inner1), inner1);
}
case (ty::ty_tag(?tid, ?tps)) {
auto variants = ty::tag_variants(cx.fcx.lcx.ccx.tcx, tid);
@ -2891,9 +2908,9 @@ fn lazily_emit_tydesc_glue(&@block_ctxt cx, int field,
T_glue_fn(lcx.ccx.tn),
"drop");
ti.drop_glue = some[ValueRef](glue_fn);
auto dg = make_drop_glue;
make_generic_glue(lcx, cx.sp, ti.ty, glue_fn,
mgghf_single(dg), ti.ty_params);
mgghf_single(make_drop_glue),
ti.ty_params);
log #fmt("--- lazily_emit_tydesc_glue DROP %s",
ty_to_str(cx.fcx.lcx.ccx.tcx, ti.ty));
}
@ -5026,7 +5043,7 @@ fn trans_lval(&@block_ctxt cx, &@ast::expr e) -> lval_result {
auto t = ty::expr_ty(cx.fcx.lcx.ccx.tcx, base);
auto offset = alt (ty::struct(cx.fcx.lcx.ccx.tcx, t)) {
case (ty::ty_box(_)) { abi::box_rc_field_body }
case (ty::ty_res(_, _)) { 1 }
case (ty::ty_res(_, _, _)) { 1 }
};
auto val = sub.bcx.build.GEP(sub.val, [C_int(0), C_int(offset)]);
ret lval_mem(sub.bcx, val);
@ -7850,10 +7867,17 @@ fn trans_res_ctor(@local_ctxt cx, &span sp, &ast::_fn dtor,
auto tup_t = ty::mk_imm_tup(cx.ccx.tcx, [ty::mk_int(cx.ccx.tcx), arg_t]);
auto arg = load_if_immediate
(bcx, fcx.llargs.get(dtor.decl.inputs.(0).id), arg_t);
auto dst = GEP_tup_like(bcx, tup_t, fcx.llretptr, [0, 1]);
auto llretptr = fcx.llretptr;
if (ty::type_has_dynamic_size(cx.ccx.tcx, ret_t)) {
auto llret_t = T_ptr(T_struct([T_i32(), llvm::LLVMTypeOf(arg)]));
llretptr = bcx.build.BitCast(llretptr, llret_t);
}
auto dst = GEP_tup_like(bcx, tup_t, llretptr, [0, 1]);
bcx = dst.bcx;
bcx = copy_val(bcx, INIT, dst.val, arg, arg_t).bcx;
auto flag = GEP_tup_like(bcx, tup_t, fcx.llretptr, [0, 0]);
auto flag = GEP_tup_like(bcx, tup_t, llretptr, [0, 0]);
bcx = flag.bcx;
bcx.build.Store(C_int(1), flag.val);
bcx.build.RetVoid();
@ -7973,7 +7997,7 @@ fn trans_item(@local_ctxt cx, &ast::item item) {
trans_res_ctor(cx, item.span, dtor, ctor_id, tps);
// Create a function for the destructor
auto lldtor_decl = cx.ccx.item_ids.get(item.id);
trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id);
trans_fn(cx, item.span, dtor, lldtor_decl, none, tps, dtor_id)
}
case (ast::item_mod(?m)) {
auto sub_cx =

View File

@ -268,7 +268,7 @@ tag sty {
ty_fn(ast::proto, vec[arg], t, controlflow, vec[@constr_def]);
ty_native_fn(ast::native_abi, vec[arg], t);
ty_obj(vec[method]);
ty_res(def_id, t);
ty_res(def_id, t, vec[t]);
ty_var(int); // type variable
ty_param(uint); // fn/tag type param
ty_type;
@ -497,7 +497,12 @@ fn mk_raw_ty(&ctxt cx, &sty st, &option::t[str] cname) -> raw_t {
m.output);
}
}
case (ty_res(_, ?tt)) { derive_flags_t(cx, has_params, has_vars, tt);}
case (ty_res(_, ?tt, ?tps)) {
derive_flags_t(cx, has_params, has_vars, tt);
for (t tt in tps) {
derive_flags_t(cx, has_params, has_vars, tt);
}
}
}
ret rec(struct=st,
cname=cname,
@ -604,8 +609,8 @@ fn mk_obj(&ctxt cx, &vec[method] meths) -> t {
ret gen_ty(cx, ty_obj(meths));
}
fn mk_res(&ctxt cx, &ast::def_id did, &t inner) -> t {
ret gen_ty(cx, ty_res(did, inner));
fn mk_res(&ctxt cx, &ast::def_id did, &t inner, &vec[t] tps) -> t {
ret gen_ty(cx, ty_res(did, inner, tps));
}
fn mk_var(&ctxt cx, int v) -> t { ret gen_ty(cx, ty_var(v)); }
@ -689,7 +694,10 @@ fn walk_ty(&ctxt cx, ty_walk walker, t ty) {
walk_ty(cx, walker, m.output);
}
}
case (ty_res(_, ?sub)) { walk_ty(cx, walker, sub); }
case (ty_res(_, ?sub, ?tps)) {
walk_ty(cx, walker, sub);
for (t tp in tps) { walk_ty(cx, walker, tp); }
}
case (ty_var(_)) {/* no-op */ }
case (ty_param(_)) {/* no-op */ }
}
@ -822,8 +830,11 @@ fn fold_ty(&ctxt cx, fold_mode fld, t ty_0) -> t {
}
ty = copy_cname(cx, mk_obj(cx, new_methods), ty);
}
case (ty_res(?did, ?subty)) {
ty = copy_cname(cx, mk_res(cx, did, fold_ty(cx, fld, subty)), ty);
case (ty_res(?did, ?subty, ?tps)) {
auto new_tps = [];
for (t tp in tps) { new_tps += [fold_ty(cx, fld, tp)]; }
ty = copy_cname(cx, mk_res(cx, did, fold_ty(cx, fld, subty),
new_tps), ty);
}
case (ty_var(?id)) {
alt (fld) {
@ -894,7 +905,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
case (ty_tag(_, _)) { ret true; }
case (ty_fn(_, _, _, _, _)) { ret true; }
case (ty_obj(_)) { ret true; }
case (ty_res(_, _)) { ret true; }
case (ty_res(_, _, _)) { ret true; }
case (ty_ivec(_)) { ret true; }
case (ty_istr) { ret true; }
case (_) { ret false; }
@ -903,7 +914,7 @@ fn type_is_structural(&ctxt cx, &t ty) -> bool {
fn type_is_copyable(&ctxt cx, &t ty) -> bool {
ret alt (struct(cx, ty)) {
case (ty_res(_, _)) { false }
case (ty_res(_, _, _)) { false }
case (_) { true }
};
}
@ -1050,7 +1061,10 @@ fn type_has_pointers(&ctxt cx, &t ty) -> bool {
if (type_has_pointers(cx, tup_ty)) { result = true; }
}
}
case (ty_res(?did, ?inner)) { result = type_has_pointers(cx, inner); }
case (ty_res(?did, ?inner, ?tps)) {
result = type_has_pointers
(cx, substitute_type_params(cx, tps, inner));
}
case (_) { result = true; }
}
@ -1114,7 +1128,12 @@ fn type_has_dynamic_size(&ctxt cx, &t ty) -> bool {
case (ty_fn(_,_,_,_,_)) { ret false; }
case (ty_native_fn(_,_,_)) { ret false; }
case (ty_obj(_)) { ret false; }
case (ty_res(_, ?sub)) { ret type_has_dynamic_size(cx, sub); }
case (ty_res(_, ?sub, ?tps)) {
for (t tp in tps) {
if (type_has_dynamic_size(cx, tp)) { ret true; }
}
ret type_has_dynamic_size(cx, sub);
}
case (ty_var(_)) { fail "ty_var in type_has_dynamic_size()"; }
case (ty_param(_)) { ret true; }
case (ty_type) { ret false; }
@ -1225,7 +1244,10 @@ fn type_owns_heap_mem(&ctxt cx, &t ty) -> bool {
if (type_owns_heap_mem(cx, f.mt.ty)) { result = true; }
}
}
case (ty_res(_, ?inner)) { result = type_owns_heap_mem(cx, inner); }
case (ty_res(_, ?inner, ?tps)) {
result = type_owns_heap_mem
(cx, substitute_type_params(cx, tps, inner));
}
case (ty_ptr(_)) { result = false; }
case (ty_port(_)) { result = false; }
@ -1337,7 +1359,11 @@ fn hash_type_structure(&sty st) -> uint {
case (ty_native) { ret 33u; }
case (ty_bot) { ret 34u; }
case (ty_ptr(?mt)) { ret hash_subty(35u, mt.ty); }
case (ty_res(?did, ?sub)) { ret hash_subty(hash_def(18u, did), sub); }
case (ty_res(?did, ?sub, ?tps)) {
auto h = hash_subty(hash_def(18u, did), sub);
for (t tp in tps) { h += h << 5u + hash_ty(tp); }
ret h;
}
}
}
@ -1598,10 +1624,18 @@ fn equal_type_structures(&sty a, &sty b) -> bool {
case (_) { ret false; }
}
}
case (ty_res(?id_a, ?inner_a)) {
case (ty_res(?id_a, ?inner_a, ?tps_a)) {
alt (b) {
case (ty_res(?id_b, ?inner_b)) {
ret equal_def(id_a, id_b) && ret eq_ty(inner_a, inner_b);
case (ty_res(?id_b, ?inner_b, ?tps_b)) {
if (!equal_def(id_a, id_b) || !eq_ty(inner_a, inner_b)) {
ret false;
}
auto i = 0u;
for (t tp_a in tps_a) {
if (!eq_ty(tp_a, tps_b.(i))) { ret false; }
i += 1u;
}
ret true;
}
case (_) { ret false; }
}
@ -2394,17 +2428,30 @@ mod unify {
case (_) { ret ures_err(terr_mismatch); }
}
}
case (ty::ty_res(?ex_id, ?ex_inner)) {
case (ty::ty_res(?ex_id, ?ex_inner, ?ex_tps)) {
alt (struct(cx.tcx, actual)) {
case (ty::ty_res(?act_id, ?act_inner)) {
case (ty::ty_res(?act_id, ?act_inner, ?act_tps)) {
if (ex_id._0 != act_id._0 || ex_id._1 != act_id._1) {
ret ures_err(terr_mismatch);
}
auto result = unify_step(cx, ex_inner, act_inner);
alt (result) {
case (ures_ok(?res_inner)) {
ret ures_ok(mk_res(cx.tcx, act_id,
res_inner));
auto i = 0u;
auto res_tps = [];
for (t ex_tp in ex_tps) {
auto result =
unify_step(cx, ex_tp, act_tps.(i));
alt (result) {
case (ures_ok(?rty)) {
vec::push(res_tps, rty);
}
case (_) { ret result; }
}
i += 1u;
}
ret ures_ok(mk_res(cx.tcx, act_id, res_inner,
res_tps));
}
case (_) { ret result; }
}

View File

@ -439,6 +439,15 @@ mod write {
mod collect {
type ctxt = rec(ty::ctxt tcx);
fn mk_ty_params(&@ctxt cx, uint n) -> vec[ty::t] {
auto tps = [];
auto i = 0u;
while (i < n) {
tps += [ty::mk_param(cx.tcx, i)];
i += 1u;
}
ret tps;
}
fn ty_of_fn_decl(&@ctxt cx, &fn(&@ast::ty) -> ty::t convert,
&fn(&ast::arg) -> arg ty_of_arg, &ast::fn_decl decl,
ast::proto proto, &vec[ast::ty_param] ty_params,
@ -581,21 +590,17 @@ mod collect {
case (ast::item_res(?f, _, ?tps, _)) {
auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
auto t_res = tup(vec::len(tps), ty::mk_res
(cx.tcx, local_def(it.id), t_arg.ty));
(cx.tcx, local_def(it.id), t_arg.ty,
mk_ty_params(cx, vec::len(tps))));
cx.tcx.tcache.insert(local_def(it.id), t_res);
ret t_res;
}
case (ast::item_tag(_, ?tps)) {
// Create a new generic polytype.
let vec[ty::t] subtys = [];
auto i = 0u;
for (ast::ty_param tp in tps) {
subtys += [ty::mk_param(cx.tcx, i)];
i += 1u;
}
auto t = ty::mk_tag(cx.tcx, local_def(it.id), subtys);
auto ty_param_count = vec::len[ast::ty_param](tps);
let vec[ty::t] subtys = mk_ty_params(cx, ty_param_count);
auto t = ty::mk_tag(cx.tcx, local_def(it.id), subtys);
auto tpt = tup(ty_param_count, t);
cx.tcx.tcache.insert(local_def(it.id), tpt);
ret tpt;
@ -631,13 +636,8 @@ mod collect {
&vec[ast::ty_param] ty_params) {
// Create a set of parameter types shared among all the variants.
let vec[ty::t] ty_param_tys = [];
auto i = 0u;
for (ast::ty_param tp in ty_params) {
ty_param_tys += [ty::mk_param(cx.tcx, i)];
i += 1u;
}
auto ty_param_count = vec::len[ast::ty_param](ty_params);
let vec[ty::t] ty_param_tys = mk_ty_params(cx, ty_param_count);
for (ast::variant variant in variants) {
// Nullary tag constructors get turned into constants; n-ary tag
// constructors get turned into functions.
@ -737,7 +737,8 @@ mod collect {
}
case (ast::item_res(?f, ?dtor_id, ?tps, ?ctor_id)) {
auto t_arg = ty_of_arg(cx, f.decl.inputs.(0));
auto t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty);
auto t_res = ty::mk_res(cx.tcx, local_def(it.id), t_arg.ty,
mk_ty_params(cx, vec::len(tps)));
auto t_ctor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
t_res, ast::return, []);
auto t_dtor = ty::mk_fn(cx.tcx, ast::proto_fn, [t_arg],
@ -1527,7 +1528,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
case (ast::deref) {
alt (structure_of(fcx, expr.span, oper_t)) {
case (ty::ty_box(?inner)) { oper_t = inner.ty; }
case (ty::ty_res(_, ?inner)) { oper_t = inner; }
case (ty::ty_res(_, ?inner, _)) { oper_t = inner; }
case (_) {
auto s = "dereferencing non-box type: " +
ty_to_str(fcx.ccx.tcx, oper_t);

View File

@ -0,0 +1,13 @@
resource finish[T](rec(T val, fn(&T) fin) arg) {
arg.fin(arg.val);
}
fn main() {
auto box = @mutable 10;
fn dec_box(&@mutable int i) { *i -= 1; }
{
auto i <- finish(rec(val=box, fin=dec_box));
}
assert(*box == 9);
}