From 86f16b90cd694cd706469bb42737e63b1d9c1fdc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 Jun 2011 14:46:17 +0200 Subject: [PATCH] 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. --- src/comp/lib/llvm.rs | 7 +++ src/comp/metadata/tydecode.rs | 6 +- src/comp/metadata/tyencode.rs | 6 +- src/comp/middle/alias.rs | 2 +- src/comp/middle/trans.rs | 74 +++++++++++++++-------- src/comp/middle/ty.rs | 87 +++++++++++++++++++++------ src/comp/middle/typeck.rs | 33 +++++----- src/test/run-pass/resource-generic.rs | 13 ++++ 8 files changed, 163 insertions(+), 65 deletions(-) create mode 100644 src/test/run-pass/resource-generic.rs diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs index 460148ad1ee..b671b2485c0 100644 --- a/src/comp/lib/llvm.rs +++ b/src/comp/lib/llvm.rs @@ -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) { diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 300fc2c6975..353eb0928c6 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -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); } diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 9ba314ccacc..51cd5fcc89a 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -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'); diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 87ad6096d33..b7f58dc4103 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -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)); diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 2f19de9230f..c14938a5b61 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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 = diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs index f669970898e..0d3be6b041d 100644 --- a/src/comp/middle/ty.rs +++ b/src/comp/middle/ty.rs @@ -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; } } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index ea5da34c773..4230a4967cd 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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); diff --git a/src/test/run-pass/resource-generic.rs b/src/test/run-pass/resource-generic.rs new file mode 100644 index 00000000000..7be26e89c21 --- /dev/null +++ b/src/test/run-pass/resource-generic.rs @@ -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); +}