提交 e1dc40b2 编写于 作者: M Marijn Haverbeke

More work on translating dictionary-passing

Reached a point where simple uses of interfaces without bounds work.

Issue #1227
上级 45b153ad
......@@ -173,8 +173,9 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
time(time_passes, "const checking",
bind middle::check_const::check_crate(sess, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars);
let method_map = time(time_passes, "typechecking",
bind typeck::check_crate(ty_cx, impl_map, crate));
let (method_map, dict_map) =
time(time_passes, "typechecking",
bind typeck::check_crate(ty_cx, impl_map, crate));
time(time_passes, "block-use checking",
bind middle::block_use::check_crate(ty_cx, crate));
time(time_passes, "function usage",
......@@ -202,7 +203,7 @@ fn compile_input(sess: session::session, cfg: ast::crate_cfg, input: str,
bind trans::trans_crate(sess, crate, ty_cx,
outputs.obj_filename, exp_map, ast_map,
mut_map, copy_map, last_uses,
method_map));
method_map, dict_map));
time(time_passes, "LLVM passes",
bind link::write::run_passes(sess, llmod, outputs.obj_filename));
......
......@@ -993,7 +993,8 @@ fn tys_str(names: type_names, outer: [TypeRef], tys: [TypeRef]) -> str {
}
10 {
let el_ty = llvm::LLVMGetElementType(ty);
ret "[" + type_to_str_inner(names, outer, el_ty) + "]";
ret "[" + type_to_str_inner(names, outer, el_ty) + " x " +
uint::str(llvm::LLVMGetArrayLength(ty)) + "]";
}
11 {
let i: uint = 0u;
......
......@@ -98,9 +98,14 @@ fn type_of_fn(cx: @crate_ctxt, sp: span, is_method: bool, inputs: [ty::arg],
// Args >2: ty params, if not acquired via capture...
if !is_method {
// FIXME[impl] Also add args for the dicts
for _param in params {
for bounds in params {
atys += [T_ptr(cx.tydesc_type)];
for bound in *bounds {
alt bound {
ty::bound_iface(_) { atys += [T_ptr(T_dict())]; }
_ {}
}
}
}
}
// ... then explicit args.
......@@ -905,7 +910,10 @@ fn linearizer(r: @rr, t: ty::t) {
ty::ty_param(pid, _) {
let seen: bool = false;
for d: uint in r.defs { if d == pid { seen = true; } }
if !seen { r.vals += [r.cx.fcx.lltydescs[pid]]; r.defs += [pid]; }
if !seen {
r.vals += [r.cx.fcx.lltyparams[pid].desc];
r.defs += [pid];
}
}
_ { }
}
......@@ -1041,8 +1049,9 @@ fn get_tydesc(cx: @block_ctxt, t: ty::t, escapes: bool,
// Is the supplied type a type param? If so, return the passed-in tydesc.
alt ty::type_param(bcx_tcx(cx), t) {
some(id) {
if id < vec::len(cx.fcx.lltydescs) {
ret {kind: tk_param, result: rslt(cx, cx.fcx.lltydescs[id])};
if id < vec::len(cx.fcx.lltyparams) {
ret {kind: tk_param,
result: rslt(cx, cx.fcx.lltyparams[id].desc)};
} else {
bcx_tcx(cx).sess.span_bug(cx.sp,
"Unbound typaram in get_tydesc: " +
......@@ -1205,10 +1214,7 @@ fn make_generic_glue_inner(cx: @local_ctxt, sp: span, t: ty::t,
p += 1u;
}
// FIXME: Implement some kind of freeze operation in the standard library.
let lltydescs_frozen = [];
for lltydesc: ValueRef in lltydescs { lltydescs_frozen += [lltydesc]; }
fcx.lltydescs = lltydescs_frozen;
fcx.lltyparams = vec::map_mut(lltydescs, {|d| {desc: d, dicts: none}});
let bcx = new_top_block_ctxt(fcx);
let lltop = bcx.llbb;
......@@ -2558,11 +2564,13 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
ret next_cx;
}
type generic_info =
{item_type: ty::t,
static_tis: [option::t<@tydesc_info>],
tydescs: [ValueRef],
param_bounds: @[ty::param_bounds]};
type generic_info = {
item_type: ty::t,
static_tis: [option::t<@tydesc_info>],
tydescs: [ValueRef],
param_bounds: @[ty::param_bounds],
origins: option::t<typeck::dict_res>
};
tag lval_kind {
temporary; //< Temporary value passed by value if of immediate type
......@@ -2571,7 +2579,12 @@ fn trans_do_while(cx: @block_ctxt, body: ast::blk, cond: @ast::expr) ->
}
type local_var_result = {val: ValueRef, kind: lval_kind};
type lval_result = {bcx: @block_ctxt, val: ValueRef, kind: lval_kind};
tag callee_env { obj_env(ValueRef); null_env; is_closure; }
tag callee_env {
null_env;
is_closure;
obj_env(ValueRef);
dict_env(ValueRef, ValueRef);
}
type lval_maybe_callee = {bcx: @block_ctxt,
val: ValueRef,
kind: lval_kind,
......@@ -2630,11 +2643,11 @@ fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
bcx = td.bcx;
tydescs += [td.val];
}
let bounds = ty::lookup_item_type(ccx.tcx, fn_id).bounds;
gen = some({item_type: tpt.ty,
static_tis: tis,
tydescs: tydescs,
param_bounds: bounds});
param_bounds: tpt.bounds,
origins: ccx.dict_map.find(id)});
}
ret {bcx: bcx, val: val, kind: owned, env: null_env, generic: gen};
}
......@@ -2843,17 +2856,6 @@ fn expr_is_lval(bcx: @block_ctxt, e: @ast::expr) -> bool {
ty::expr_is_lval(ccx.method_map, ccx.tcx, e)
}
// This is for impl methods, not obj methods.
fn trans_method_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
did: ast::def_id) -> lval_maybe_callee {
let tz = [], tr = [];
let basety = ty::expr_ty(bcx_tcx(bcx), base);
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
type_of_or_i8(bcx, basety), tz, tr, base);
let val = PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx)));
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
}
fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
alt e.node {
ast::expr_path(p) { ret trans_path(bcx, p, e.id); }
......@@ -2862,10 +2864,11 @@ fn trans_callee(bcx: @block_ctxt, e: @ast::expr) -> lval_maybe_callee {
if !expr_is_lval(bcx, e) {
alt bcx_ccx(bcx).method_map.find(e.id) {
some(typeck::method_static(did)) { // An impl method
ret trans_method_callee(bcx, e, base, did);
ret trans_impl::trans_static_callee(bcx, e, base, did);
}
some(typeck::method_param(_)) {
fail "not implemented"; // FIXME[impl]
some(typeck::method_param(iid, off, p, b)) {
ret trans_impl::trans_dict_callee(
bcx, e, base, iid, off, p, b);
}
none. { // An object method
let of = trans_object_field(bcx, base, ident);
......@@ -2936,7 +2939,7 @@ fn maybe_add_env(bcx: @block_ctxt, c: lval_maybe_callee)
-> (lval_kind, ValueRef) {
alt c.env {
is_closure. { (c.kind, c.val) }
obj_env(_) {
obj_env(_) | dict_env(_, _) {
fail "Taking the value of a method does not work yet (issue #435)";
}
null_env. {
......@@ -3149,7 +3152,23 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef,
alt gen {
some(g) {
lazily_emit_all_generic_info_tydesc_glues(cx, g);
lltydescs = g.tydescs;
let i = 0u, n_orig = 0u;
for param in *g.param_bounds {
lltydescs += [g.tydescs[i]];
for bound in *param {
alt bound {
ty::bound_iface(_) {
let res = trans_impl::get_dict(
bcx, option::get(g.origins)[n_orig]);
lltydescs += [res.val];
bcx = res.bcx;
n_orig += 1u;
}
_ {}
}
}
i += 1u;
}
args = ty::ty_fn_args(tcx, g.item_type);
retty = ty::ty_fn_ret(tcx, g.item_type);
}
......@@ -3220,12 +3239,13 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
let bcx = f_res.bcx;
let faddr = f_res.val;
let llenv;
let llenv, dict_param = none;
alt f_res.env {
null_env. {
llenv = llvm::LLVMGetUndef(T_opaque_boxed_closure_ptr(bcx_ccx(cx)));
}
obj_env(e) { llenv = e; }
dict_env(dict, e) { llenv = e; dict_param = some(dict); }
is_closure. {
// It's a closure. Have to fetch the elements
if f_res.kind == owned {
......@@ -3244,6 +3264,7 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
trans_args(bcx, llenv, f_res.generic, args, fn_expr_ty, dest);
bcx = args_res.bcx;
let llargs = args_res.args;
option::may(dict_param) {|dict| llargs = [dict] + llargs}
let llretslot = args_res.retslot;
/* If the block is terminated,
......@@ -3306,8 +3327,7 @@ fn invoke_(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
// cleanups to run
if bcx.unreachable { ret bcx; }
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
invoker(bcx, llfn, llargs,
normal_bcx.llbb,
invoker(bcx, llfn, llargs, normal_bcx.llbb,
get_landing_pad(bcx, to_zero, to_revoke));
ret normal_bcx;
}
......@@ -4351,7 +4371,7 @@ fn new_fn_ctxt_w_id(cx: @local_ctxt, sp: span, llfndecl: ValueRef,
llobjfields: new_int_hash::<ValueRef>(),
lllocals: new_int_hash::<local_val>(),
llupvars: new_int_hash::<ValueRef>(),
mutable lltydescs: [],
mutable lltyparams: [],
derived_tydescs: ty::new_ty_hash(),
id: id,
ret_style: rstyle,
......@@ -4393,10 +4413,22 @@ fn create_llargs_for_fn_args(cx: @fn_ctxt, ty_self: self_arg,
obj_self(_) {}
_ {
for tp in ty_params {
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n);
assert (llarg as int != 0);
cx.lltydescs += [llarg];
let lltydesc = llvm::LLVMGetParam(cx.llfn, arg_n), dicts = none;
arg_n += 1u;
for bound in *fcx_tcx(cx).ty_param_bounds.get(tp.id) {
alt bound {
ty::bound_iface(_) {
let dict = llvm::LLVMGetParam(cx.llfn, arg_n);
arg_n += 1u;
dicts = some(alt dicts {
none. { [dict] }
some(ds) { ds + [dict] }
});
}
_ {}
}
}
cx.lltyparams += [{desc: lltydesc, dicts: dicts}];
}
}
}
......@@ -4485,7 +4517,7 @@ fn populate_fn_ctxt_from_llself(fcx: @fn_ctxt, llself: val_self_pair) {
let lltyparam: ValueRef =
GEPi(bcx, obj_typarams, [0, i]);
lltyparam = Load(bcx, lltyparam);
fcx.lltydescs += [lltyparam];
fcx.lltyparams += [{desc: lltyparam, dicts: none}];
i += 1;
}
i = 0;
......@@ -5582,7 +5614,8 @@ fn write_abi_version(ccx: @crate_ctxt) {
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
output: str, emap: resolve::exp_map, amap: ast_map::map,
mut_map: mut::mut_map, copy_map: alias::copy_map,
last_uses: last_use::last_uses, method_map: typeck::method_map)
last_uses: last_use::last_uses, method_map: typeck::method_map,
dict_map: typeck::dict_map)
-> (ModuleRef, link::link_meta) {
let sha = std::sha1::mk_sha1();
let link_meta = link::build_link_meta(sess, *crate, output, sha);
......@@ -5659,6 +5692,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
copy_map: copy_map,
last_uses: last_uses,
method_map: method_map,
dict_map: dict_map,
stats:
{mutable n_static_tydescs: 0u,
mutable n_derived_tydescs: 0u,
......
......@@ -82,17 +82,21 @@
// Given a closure ty, emits a corresponding tuple ty
fn mk_closure_ty(tcx: ty::ctxt,
ck: ty::closure_kind,
n_bound_tds: uint,
ty_params: [fn_ty_param],
bound_data_ty: ty::t)
-> ty::t {
let tydesc_ty = alt ck {
ty::closure_block. | ty::closure_shared. { ty::mk_type(tcx) }
ty::closure_send. { ty::mk_send_type(tcx) }
};
ret ty::mk_tup(tcx, [
tydesc_ty,
ty::mk_tup(tcx, vec::init_elt(tydesc_ty, n_bound_tds)),
bound_data_ty]);
let param_ptrs = [];
for tp in ty_params {
param_ptrs += [tydesc_ty];
option::may(tp.dicts) {|dicts|
for dict in dicts { param_ptrs += [tydesc_ty]; }
}
}
ty::mk_tup(tcx, [tydesc_ty, ty::mk_tup(tcx, param_ptrs), bound_data_ty])
}
fn shared_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
......@@ -117,7 +121,7 @@ fn send_opaque_closure_box_ty(tcx: ty::ctxt) -> ty::t {
// heap allocated closure that copies the upvars into environment.
// Otherwise, it is stack allocated and copies pointers to the upvars.
fn store_environment(
bcx: @block_ctxt, lltydescs: [ValueRef],
bcx: @block_ctxt, lltyparams: [fn_ty_param],
bound_values: [environment_value],
ck: ty::closure_kind)
-> closure_result {
......@@ -162,7 +166,7 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
}
let bound_data_ty = ty::mk_tup(tcx, bound_tys);
let closure_ty =
mk_closure_ty(tcx, ck, vec::len(lltydescs), bound_data_ty);
mk_closure_ty(tcx, ck, lltyparams, bound_data_ty);
let temp_cleanups = [];
......@@ -210,7 +214,7 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
// in the shape code. Therefore, I am using
// tps_normal, which is what we used before.
//
// let tps = tps_fn(vec::len(lltydescs));
// let tps = tps_fn(vec::len(lltyparams));
let tps = tps_normal;
let {result:closure_td, _} =
......@@ -232,10 +236,19 @@ fn maybe_clone_tydesc(bcx: @block_ctxt,
let {bcx:bcx, val:ty_params_slot} =
GEP_tup_like_1(bcx, closure_ty, closure,
[0, abi::closure_elt_ty_params]);
vec::iteri(lltydescs) { |i, td|
let ty_param_slot = GEPi(bcx, ty_params_slot, [0, i as int]);
let cloned_td = maybe_clone_tydesc(bcx, ck, td);
Store(bcx, cloned_td, ty_param_slot);
let off = 0;
for tp in lltyparams {
let cloned_td = maybe_clone_tydesc(bcx, ck, tp.desc);
Store(bcx, cloned_td, GEPi(bcx, ty_params_slot, [0, off]));
off += 1;
option::may(tp.dicts, {|dicts|
for dict in dicts {
let cast = PointerCast(bcx, dict, val_ty(cloned_td));
Store(bcx, cast, GEPi(bcx, ty_params_slot, [0, off]));
off += 1;
}
});
}
// Copy expr values into boxed bindings.
......@@ -316,7 +329,7 @@ fn build_closure(bcx0: @block_ctxt,
}
}
}
ret store_environment(bcx, copy bcx.fcx.lltydescs, env_vals, ck);
ret store_environment(bcx, copy bcx.fcx.lltyparams, env_vals, ck);
}
// Given an enclosing block context, a new function context, a closure type,
......@@ -338,13 +351,23 @@ fn load_environment(enclosing_cx: @block_ctxt,
// Populate the type parameters from the environment. We need to
// do this first because the tydescs are needed to index into
// the bindings if they are dynamically sized.
let tydesc_count = vec::len(enclosing_cx.fcx.lltydescs);
let lltydescs = GEPi(bcx, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_ty_params]);
uint::range(0u, tydesc_count) { |i|
let lltydescptr = GEPi(bcx, lltydescs, [0, i as int]);
fcx.lltydescs += [Load(bcx, lltydescptr)];
let off = 0;
for tp in copy enclosing_cx.fcx.lltyparams {
let tydesc = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
off += 1;
let dicts = option::map(tp.dicts, {|dicts|
let rslt = [];
for dict in dicts {
let dict = Load(bcx, GEPi(bcx, lltydescs, [0, off]));
rslt += [PointerCast(bcx, dict, T_ptr(T_dict()))];
off += 1;
}
rslt
});
fcx.lltyparams += [{desc: tydesc, dicts: dicts}];
}
// Populate the upvars from the environment.
......@@ -439,13 +462,22 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
let (outgoing_fty_real, lltydescs, param_bounds) = alt f_res.generic {
none. { (outgoing_fty, [], @[]) }
some(ginfo) {
for bounds in *ginfo.param_bounds {
for bound in *bounds {
alt bound {
ty::bound_iface(_) {
fail "FIXME[impl] binding bounded types not implemented";
}
_ {}
}
}
}
lazily_emit_all_generic_info_tydesc_glues(cx, ginfo);
(ginfo.item_type, ginfo.tydescs, ginfo.param_bounds)
}
};
let ty_param_count = vec::len(lltydescs);
if vec::len(bound) == 0u && ty_param_count == 0u {
if vec::len(bound) == 0u && vec::len(lltydescs) == 0u {
// Trivial 'binding': just return the closure
let lv = lval_maybe_callee_to_lval(f_res, pair_ty);
bcx = lv.bcx;
......@@ -477,7 +509,7 @@ fn trans_bind_1(cx: @block_ctxt, outgoing_fty: ty::t,
// Actually construct the closure
let {llbox, box_ty, bcx} = store_environment(
bcx, lltydescs,
bcx, vec::map(lltydescs, {|d| {desc: d, dicts: none}}),
env_vals + vec::map(bound, {|x| env_expr(x)}),
ty::closure_shared);
......@@ -603,7 +635,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
// our bound tydescs, we need to load tydescs out of the environment
// before derived tydescs are constructed. To do this, we load them
// in the load_env block.
let load_env_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
let l_bcx = new_raw_block_ctxt(fcx, fcx.llloadenv);
// The 'llenv' that will arrive in the thunk we're creating is an
// environment that will contain the values of its arguments and a pointer
......@@ -613,7 +645,7 @@ fn trans_bind_thunk(cx: @local_ctxt,
// 'boxed_closure_ty', which was determined by trans_bind.
check (type_has_static_size(ccx, boxed_closure_ty));
let llclosure_ptr_ty = type_of(ccx, sp, boxed_closure_ty);
let llclosure = PointerCast(load_env_bcx, fcx.llenv, llclosure_ptr_ty);
let llclosure = PointerCast(l_bcx, fcx.llenv, llclosure_ptr_ty);
// "target", in this context, means the function that's having some of its
// arguments bound and that will be called inside the thunk we're
......@@ -664,20 +696,32 @@ fn trans_bind_thunk(cx: @local_ctxt,
let llargs: [ValueRef] = [llretptr, lltargetenv];
// Copy in the type parameters.
// FIXME[impl] This will also have to copy the dicts
let i = 0u, ty_param_count = vec::len(param_bounds);
while i < ty_param_count {
// Silly check
check type_is_tup_like(load_env_bcx, boxed_closure_ty);
let lltyparam_ptr =
GEP_tup_like(load_env_bcx, boxed_closure_ty, llclosure,
[0, abi::box_rc_field_body,
abi::closure_elt_ty_params, i as int]);
load_env_bcx = lltyparam_ptr.bcx;
let td = Load(load_env_bcx, lltyparam_ptr.val);
llargs += [td];
fcx.lltydescs += [td];
i += 1u;
check type_is_tup_like(l_bcx, boxed_closure_ty);
let {bcx: l_bcx, val: param_record} =
GEP_tup_like(l_bcx, boxed_closure_ty, llclosure,
[0, abi::box_rc_field_body, abi::closure_elt_ty_params]);
let off = 0;
for param in param_bounds {
let dsc = Load(l_bcx, GEPi(l_bcx, param_record, [0, off])),
dicts = none;
llargs += [dsc];
off += 1;
for bound in *param {
alt bound {
ty::bound_iface(_) {
let dict = Load(l_bcx, GEPi(l_bcx, param_record, [0, off]));
dict = PointerCast(l_bcx, dict, T_ptr(T_dict()));
llargs += [dict];
off += 1;
dicts = some(alt dicts {
none. { [dict] }
some(ds) { ds + [dict] }
});
}
_ {}
}
}
fcx.lltyparams += [{desc: dsc, dicts: dicts}];
}
let a: uint = 2u; // retptr, env come first
......
......@@ -104,6 +104,7 @@
copy_map: alias::copy_map,
last_uses: last_use::last_uses,
method_map: typeck::method_map,
dict_map: typeck::dict_map,
stats: stats,
upcalls: @upcall::upcalls,
rust_object_type: TypeRef,
......@@ -130,6 +131,8 @@
tag local_val { local_mem(ValueRef); local_imm(ValueRef); }
type fn_ty_param = {desc: ValueRef, dicts: option::t<[ValueRef]>};
// Function context. Every LLVM function we create will have one of
// these.
type fn_ctxt =
......@@ -235,7 +238,7 @@
llobjfields: hashmap<ast::node_id, ValueRef>,
lllocals: hashmap<ast::node_id, local_val>,
llupvars: hashmap<ast::node_id, ValueRef>,
mutable lltydescs: [ValueRef],
mutable lltyparams: [fn_ty_param],
derived_tydescs: hashmap<ty::t, derived_tydesc_info>,
id: ast::node_id,
ret_style: ast::ret_style,
......@@ -532,11 +535,9 @@ fn T_size_t(targ_cfg: @session::config) -> TypeRef {
ret T_int(targ_cfg);
}
fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef {
unsafe {
ret llvm::LLVMFunctionType(output, to_ptr(inputs),
vec::len::<TypeRef>(inputs), False);
}
fn T_fn(inputs: [TypeRef], output: TypeRef) -> TypeRef unsafe {
ret llvm::LLVMFunctionType(output, to_ptr(inputs),
vec::len::<TypeRef>(inputs), False);
}
fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
......@@ -545,10 +546,8 @@ fn T_fn_pair(cx: @crate_ctxt, tfn: TypeRef) -> TypeRef {
fn T_ptr(t: TypeRef) -> TypeRef { ret llvm::LLVMPointerType(t, 0u); }
fn T_struct(elts: [TypeRef]) -> TypeRef {
unsafe {
ret llvm::LLVMStructType(to_ptr(elts), vec::len(elts), False);
}
fn T_struct(elts: [TypeRef]) -> TypeRef unsafe {
ret llvm::LLVMStructType(to_ptr(elts), vec::len(elts), False);
}
fn T_named_struct(name: str) -> TypeRef {
......@@ -573,6 +572,12 @@ fn T_rust_object() -> TypeRef {
ret t;
}
// A dict is, in reality, a vtable pointer followed by zero or more pointers
// to tydescs and other dicts that it closes over. But the types and number of
// those are rarely known to the code that needs to manipulate them, so they
// are described by this opaque type.
fn T_dict() -> TypeRef { T_array(T_ptr(T_i8()), 1u) }
fn T_task(targ_cfg: @session::config) -> TypeRef {
let t = T_named_struct("task");
......
......@@ -22,6 +22,40 @@ fn trans_impl(cx: @local_ctxt, name: ast::ident, methods: [@ast::method],
}
}
fn trans_self_arg(bcx: @block_ctxt, base: @ast::expr) -> result {
let tz = [], tr = [];
let basety = ty::expr_ty(bcx_tcx(bcx), base);
let {bcx, val} = trans_arg_expr(bcx, {mode: ast::by_ref, ty: basety},
T_ptr(type_of_or_i8(bcx, basety)), tz,
tr, base);
rslt(bcx, PointerCast(bcx, val, T_opaque_boxed_closure_ptr(bcx_ccx(bcx))))
}
fn trans_static_callee(bcx: @block_ctxt, e: @ast::expr, base: @ast::expr,
did: ast::def_id) -> lval_maybe_callee {
let {bcx, val} = trans_self_arg(bcx, base);
{env: obj_env(val) with lval_static_fn(bcx, did, e.id)}
}
fn trans_dict_callee(bcx: @block_ctxt, _e: @ast::expr, base: @ast::expr,
iface_id: ast::def_id, n_method: uint,
n_param: uint, n_bound: uint) -> lval_maybe_callee {
let {bcx, val} = trans_self_arg(bcx, base);
let dict = option::get(bcx.fcx.lltyparams[n_param].dicts)[n_bound];
let method = ty::iface_methods(bcx_tcx(bcx), iface_id)[n_method];
let bare_fn_ty = type_of_fn(bcx_ccx(bcx), ast_util::dummy_sp(),
false, method.fty.inputs, method.fty.output,
*method.tps);
let {inputs: bare_inputs, output} = llfn_arg_tys(bare_fn_ty);
let fn_ty = T_fn([val_ty(dict)] + bare_inputs, output);
let vtable = PointerCast(bcx, Load(bcx, GEPi(bcx, dict, [0, 0])),
T_ptr(T_array(T_ptr(fn_ty), n_method + 1u)));
let mptr = Load(bcx, GEPi(bcx, vtable, [0, n_method as int]));
{bcx: bcx, val: mptr, kind: owned,
env: dict_env(dict, val),
generic: none} // FIXME[impl] fetch generic info for method
}
fn llfn_arg_tys(ft: TypeRef) -> {inputs: [TypeRef], output: TypeRef} {
let out_ty = llvm::llvm::LLVMGetReturnType(ft);
let n_args = llvm::llvm::LLVMCountParamTypes(ft);
......@@ -35,12 +69,21 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
let real_fn = ccx.item_ids.get(m.id);
let {inputs: real_args, output: real_ret} =
llfn_arg_tys(llvm::llvm::LLVMGetElementType(val_ty(real_fn)));
let env_ty = T_ptr(T_struct([T_ptr(T_i8())] +
vec::map(extra_tps,
{|_p| T_ptr(ccx.tydesc_type)})));
// FIXME[impl] filter and pass along dicts for bounds
let wrap_args = [env_ty] + vec::slice(real_args, 0u, 2u) +
vec::slice(real_args, 2u + vec::len(extra_tps), vec::len(real_args));
let extra_ptrs = [];
for tp in extra_tps {
extra_ptrs += [T_ptr(ccx.tydesc_type)];
for bound in *tp {
alt bound {
ty::bound_iface(_) { extra_ptrs += [T_ptr(T_dict())]; }
_ {}
}
}
}
let env_ty = T_ptr(T_struct([T_ptr(T_i8())] + extra_ptrs));
let n_extra_ptrs = vec::len(extra_ptrs);
let wrap_args = [T_ptr(T_dict())] + vec::slice(real_args, 0u, 2u) +
vec::slice(real_args, 2u + vec::len(extra_ptrs), vec::len(real_args));
let llfn_ty = T_fn(wrap_args, real_ret);
let lcx = @{path: pt + ["wrapper", m.ident], module_path: [],
......@@ -50,13 +93,13 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
let fcx = new_fn_ctxt(lcx, ast_util::dummy_sp(), llfn);
let bcx = new_top_block_ctxt(fcx), lltop = bcx.llbb;
let dict = LLVMGetParam(llfn, 0u);
let dict = PointerCast(bcx, LLVMGetParam(llfn, 0u), env_ty);
// retptr, self
let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 1;
let args = [LLVMGetParam(llfn, 1u), LLVMGetParam(llfn, 2u)], i = 0u;
// saved tydescs/dicts
for extra_tp in extra_tps {
args += [load_inbounds(bcx, dict, [0, i])];
i += 1;
while i < n_extra_ptrs {
i += 1u;
args += [load_inbounds(bcx, dict, [0, i as int])];
}
// the rest of the parameters
let i = 3u, params_total = llvm::llvm::LLVMCountParamTypes(llfn_ty);
......@@ -65,7 +108,45 @@ fn trans_wrapper(ccx: @crate_ctxt, pt: [ast::ident],
i += 1u;
}
Call(bcx, ccx.item_ids.get(m.id), args);
build_return(bcx);
finish_fn(fcx, lltop);
ret llfn;
}
// FIXME[impl] cache these on the function level somehow
fn get_dict(bcx: @block_ctxt, origin: typeck::dict_origin) -> result {
let bcx = bcx, ccx = bcx_ccx(bcx);
alt origin {
typeck::dict_static(impl_did, tys, sub_origins) {
assert impl_did.crate == ast::local_crate; // FIXME[impl]
let vtable = ccx.item_ids.get(impl_did.node);
let impl_params = ty::lookup_item_type(ccx.tcx, impl_did).bounds;
let ptrs = [vtable], i = 0u, origin = 0u, ti = none;
for param in *impl_params {
let rslt = get_tydesc(bcx, tys[i], false, tps_normal, ti).result;
ptrs += [rslt.val];
bcx = rslt.bcx;
for bound in *param {
alt bound {
ty::bound_iface(_) {
let res = get_dict(bcx, sub_origins[origin]);
ptrs += [res.val];
bcx = res.bcx;
origin += 1u;
}
_ {}
}
}
i += 1u;
}
let pty = T_ptr(T_i8()), dict_ty = T_array(pty, vec::len(ptrs));
let dict = alloca(bcx, dict_ty), i = 0;
for ptr in ptrs {
Store(bcx, PointerCast(bcx, ptr, pty), GEPi(bcx, dict, [0, i]));
i += 1;
}
rslt(bcx, PointerCast(bcx, dict, T_ptr(T_dict())))
}
typeck::dict_param(_param) { fail "FIXME[impl]"; }
}
}
\ No newline at end of file
......@@ -158,7 +158,7 @@ fn trans_obj(cx: @local_ctxt, sp: span, ob: ast::_obj, ctor_id: ast::node_id,
let typarams_ty: ty::t = ty::mk_tup(ccx.tcx, tps);
let i: int = 0;
for tp: ast::ty_param in ty_params {
let typaram = bcx.fcx.lltydescs[i];
let typaram = bcx.fcx.lltyparams[i].desc;
// Silly check
check type_is_tup_like(bcx, typarams_ty);
let capture =
......
......@@ -19,10 +19,12 @@
import syntax::print::pprust::*;
export check_crate, method_map, method_origin, method_static, method_param;
export dict_map, dict_res, dict_origin, dict_static, dict_param;
tag method_origin {
method_static(ast::def_id);
method_param(uint);
// iface id, method num, param num, bound num
method_param(ast::def_id, uint, uint, uint);
}
type method_map = hashmap<ast::node_id, method_origin>;
......@@ -694,14 +696,15 @@ fn convert(cx: @ctxt, it: @ast::item) {
get_tag_variant_types(cx, tpt.ty, variants, ty_params);
}
ast::item_impl(tps, _, selfty, ms) {
ty_param_bounds(cx.tcx, m_collect, tps);
let i_bounds = ty_param_bounds(cx.tcx, m_collect, tps);
for m in ms {
let bounds = ty_param_bounds(cx.tcx, m_collect, m.tps);
let ty = ty::mk_fn(cx.tcx,
ty_of_fn_decl(cx.tcx, m_collect,
ast::proto_bare, m.decl));
cx.tcx.tcache.insert(local_def(m.id), {bounds: bounds,
ty: ty});
cx.tcx.tcache.insert(local_def(m.id),
{bounds: @(*i_bounds + *bounds),
ty: ty});
write::ty_only(cx.tcx, m.id, ty);
}
write::ty_only(cx.tcx, it.id, ast_ty_to_ty(cx.tcx, m_collect,
......@@ -1493,6 +1496,7 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
// First, see whether this is an interface-bounded parameter
alt ty::struct(tcx, ty) {
ty::ty_param(n, did) {
let bound_n = 0u;
for bound in *tcx.ty_param_bounds.get(did.node) {
alt bound {
ty::bound_iface(t) {
......@@ -1500,19 +1504,21 @@ fn lookup_method(fcx: @fn_ctxt, isc: resolve::iscopes,
ty::ty_iface(i, tps) { (i, tps) }
_ { ret none; }
};
alt vec::find(*ty::iface_methods(tcx, iid),
{|m| m.ident == name}) {
some(m) {
let ifce_methods = ty::iface_methods(tcx, iid);
alt vec::position_pred(*ifce_methods, {|m| m.ident == name}) {
some(pos) {
let m = ifce_methods[pos];
ret some({method_ty: ty::mk_fn(tcx, m.fty),
n_tps: vec::len(*m.tps),
ids: [], // FIXME[impl]
origin: method_param(n)});
origin: method_param(iid, pos, n, bound_n)});
}
_ {}
}
}
_ {}
}
bound_n += 1u;
}
ret none;
}
......@@ -2742,7 +2748,8 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
vec::pop(ccx.self_infos);
alt ifce {
some(ty) {
alt ty::struct(ccx.tcx, ast_ty_to_ty(ccx.tcx, m_check, ty)) {
let iface_ty = ast_ty_to_ty(ccx.tcx, m_check, ty);
alt ty::struct(ccx.tcx, iface_ty) {
ty::ty_iface(did, tys) {
for if_m in *ty::iface_methods(ccx.tcx, did) {
alt vec::find(my_methods, {|m| if_m.ident == m.ident}) {
......@@ -2759,6 +2766,9 @@ fn check_item(ccx: @crate_ctxt, it: @ast::item) {
}
}
}
let tpt = {bounds: ty_param_bounds(ccx.tcx, m_check, tps),
ty: iface_ty};
ccx.tcx.tcache.insert(local_def(it.id), tpt);
}
_ {
ccx.tcx.sess.span_err(ty.span, "can only implement interface \
......@@ -2854,12 +2864,22 @@ fn check_for_main_fn(tcx: ty::ctxt, crate: @ast::crate) {
}
}
// Resolutions for bounds of all parameters, left to right, for a given path.
type dict_res = @[dict_origin];
tag dict_origin {
dict_static(ast::def_id, [ty::t], dict_res);
dict_param(uint);
}
type dict_map = hashmap<ast::node_id, dict_res>;
// Detect points where an interface-bounded type parameter is instantiated,
// resolve the impls for the parameters.
fn resolve_vtables(tcx: ty::ctxt, impl_map: resolve::impl_map,
crate: @ast::crate) {
type ccx = {tcx: ty::ctxt, impl_map: resolve::impl_map};
let cx = {tcx: tcx, impl_map: impl_map};
fn resolve_dicts(tcx: ty::ctxt, impl_map: resolve::impl_map,
crate: @ast::crate) -> dict_map {
type ccx = {tcx: ty::ctxt,
impl_map: resolve::impl_map,
dict_map: dict_map};
let cx = {tcx: tcx, impl_map: impl_map, dict_map: new_int_hash()};
fn resolve_expr(ex: @ast::expr, cx: ccx, v: visit::vt<ccx>) {
alt ex.node {
ast::expr_path(_) {
......@@ -2868,18 +2888,15 @@ fn resolve_expr(ex: @ast::expr, cx: ccx, v: visit::vt<ccx>) {
alt substs.substs {
some(ts) {
let did = ast_util::def_id_of_def(cx.tcx.def_map.get(ex.id));
let item_ty = ty::lookup_item_type(cx.tcx, did), i = 0u;
for s_ty in ts {
for bound in *item_ty.bounds[i] {
alt bound {
ty::bound_iface(i_ty) {
let impls = cx.impl_map.get(ex.id);
lookup_impl(cx, impls, ex.span, s_ty, i_ty);
}
_ {}
}
}
i += 1u;
let item_ty = ty::lookup_item_type(cx.tcx, did);
if vec::any(*item_ty.bounds, {|bs|
vec::any(*bs, {|b|
alt b { ty::bound_iface(_) { true } _ { false } }
})
}) {
let impls = cx.impl_map.get(ex.id);
cx.dict_map.insert(ex.id, lookup_dicts(
cx.tcx, impls, ex.span, *item_ty.bounds, ts));
}
}
_ {}
......@@ -2889,52 +2906,94 @@ fn resolve_expr(ex: @ast::expr, cx: ccx, v: visit::vt<ccx>) {
}
visit::visit_expr(ex, cx, v);
}
fn lookup_impl(cx: ccx, isc: resolve::iscopes, sp: span,
sub_ty: ty::t, iface_ty: ty::t) {
let iface_id = alt ty::struct(cx.tcx, iface_ty) {
fn lookup_dicts(tcx: ty::ctxt, isc: resolve::iscopes, sp: span,
bounds: [ty::param_bounds], tys: [ty::t])
-> dict_res {
let result = [], i = 0u;
for ty in tys {
for bound in *bounds[i] {
alt bound {
ty::bound_iface(i_ty) {
result += [lookup_dict(tcx, isc, sp, ty, i_ty)];
}
_ {}
}
}
i += 1u;
}
@result
}
fn lookup_dict(tcx: ty::ctxt, isc: resolve::iscopes, sp: span,
ty: ty::t, iface_ty: ty::t) -> dict_origin {
let iface_id = alt ty::struct(tcx, iface_ty) {
ty::ty_iface(did, _) { did }
_ { ret; }
_ { tcx.sess.abort_if_errors(); fail; }
};
// FIXME check against bounded param types
let found = false;
std::list::iter(isc) {|impls|
if found { ret; }
for im in *impls {
if im.iface_did == some(iface_id) {
let self_ty = impl_self_ty(cx.tcx, im.did).ty;
let params = @mutable [mutable];
alt ty::unify::unify(sub_ty, self_ty,
ty::unify::bind_params(params),
cx.tcx) {
ures_ok(_) {
if found {
cx.tcx.sess.span_err(
sp, "multiple applicable implementations in \
scope");
} else {
found = true;
}
alt ty::struct(tcx, ty) {
ty::ty_param(n, did) {
for bound in *tcx.ty_param_bounds.get(did.node) {
alt bound {
ty::bound_iface(ity) {
alt ty::struct(tcx, ity) {
ty::ty_iface(idid, _) {
if did == idid { ret dict_param(n); }
}
_ {}
}
}
_ {}
}
}
}
_ {
let found = none;
std::list::iter(isc) {|impls|
if option::is_some(found) { ret; }
for im in *impls {
if im.iface_did == some(iface_id) {
let self_ty = impl_self_ty(tcx, im.did).ty;
let params = @mutable [mutable];
alt ty::unify::unify(ty, self_ty,
ty::unify::bind_params(params),
tcx) {
ures_ok(_) {
if option::is_some(found) {
tcx.sess.span_err(
sp, "multiple applicable implementations \
in scope");
} else {
let params = vec::map_mut(
*params, {|p| option::get(p)});
// FIXME[impl] check for sub-bounds
found = some(dict_static(
im.did, params, @[]));
}
}
_ {}
}
}
}
}
alt found {
some(rslt) { ret rslt; }
_ {}
}
}
}
if !found {
cx.tcx.sess.span_err(
sp, "failed to find an implementation of interface " +
ty_to_str(cx.tcx, iface_ty) + " for " +
ty_to_str(cx.tcx, sub_ty));
}
tcx.sess.span_fatal(
sp, "failed to find an implementation of interface " +
ty_to_str(tcx, iface_ty) + " for " +
ty_to_str(tcx, ty));
}
visit::visit_crate(*crate, cx, visit::mk_vt(@{
visit_expr: resolve_expr
with *visit::default_visitor()
}));
cx.dict_map
}
fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
crate: @ast::crate) -> method_map {
crate: @ast::crate) -> (method_map, dict_map) {
collect::collect_item_types(tcx, crate);
let ccx = @{mutable self_infos: [],
......@@ -2947,10 +3006,10 @@ fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
bind check_native_item(ccx, _)
with *visit::default_simple_visitor()});
visit::visit_crate(*crate, (), visit);
resolve_vtables(tcx, impl_map, crate);
let dict_map = resolve_dicts(tcx, impl_map, crate);
check_for_main_fn(tcx, crate);
tcx.sess.abort_if_errors();
ccx.method_map
(ccx.method_map, dict_map)
}
//
// Local Variables:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册