Monomorphize methods and bounded parameters

Issue #1736
This commit is contained in:
Marijn Haverbeke 2012-02-09 11:17:11 +01:00
parent 149d1d4a6e
commit 1dc5e1aa94
6 changed files with 143 additions and 39 deletions

View file

@ -10,7 +10,7 @@ type path = [path_elt];
enum ast_node {
node_item(@item, @path),
node_native_item(@native_item, @path),
node_method(@method, @path),
node_method(@method, node_id, @path),
node_variant(variant, def_id, @path),
node_expr(@expr),
// Locals are numbered, because the alias analysis needs to know in which
@ -69,7 +69,7 @@ fn map_item(i: @item, cx: ctx, v: vt) {
cx.map.insert(i.id, node_item(i, @cx.path));
alt i.node {
item_impl(_, _, _, ms) {
for m in ms { cx.map.insert(m.id, node_method(m, @cx.path)); }
for m in ms { cx.map.insert(m.id, node_method(m, i.id, @cx.path)); }
}
item_res(_, _, _, dtor_id, ctor_id) {
cx.map.insert(ctor_id, node_res_ctor(i));

View file

@ -802,7 +802,7 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
bound to non-function"); }
}
}
ast_map::node_method(method, _) {
ast_map::node_method(method, _, _) {
(method.ident, method.decl.output, method.id)
}
ast_map::node_res_ctor(item) {

View file

@ -2450,10 +2450,12 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
some(val) { ret some(val); }
none {}
}
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
let mono_ty = ty::substitute_type_params(ccx.tcx, substs, tpt.ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty, []);
let lldecl;
let psubsts = some({tys: substs, dicts: dicts, bounds: tpt.bounds});
alt ccx.tcx.items.get(fn_id.node) {
ast_map::node_item(item, pt) {
let pt = *pt + [path_name(item.ident)];
@ -2462,10 +2464,10 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
alt item.node {
ast::item_fn(decl, _, body) {
trans_fn(ccx, pt, decl, body, lldecl, no_self, [],
some(substs), fn_id.node);
psubsts, fn_id.node);
}
ast::item_res(decl, _, _, _, ctor_id) {
trans_res_ctor(ccx, pt, decl, ctor_id, [], some(substs), lldecl);
trans_res_ctor(ccx, pt, decl, ctor_id, [], psubsts, lldecl);
}
_ { fail "Unexpected item type"; }
}
@ -2478,7 +2480,16 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
let this_tv = option::get(vec::find(*tvs, {|tv|
tv.id.node == fn_id.node}));
trans_enum_variant(ccx, enum_id.node, v, this_tv.disr_val,
vec::len(*tvs) == 1u, [], some(substs), lldecl);
vec::len(*tvs) == 1u, [], psubsts, lldecl);
}
ast_map::node_method(mth, impl_id, pt) {
let pt = *pt + [path_name(mth.ident)];
let s = mangle_exported_name(ccx, pt, mono_ty);
lldecl = decl_cdecl_fn(ccx.llmod, s, llfty);
let selfty = ty::node_id_to_type(ccx.tcx, impl_id);
let selfty = ty::substitute_type_params(ccx.tcx, substs, selfty);
trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
impl_self(selfty), [], psubsts, fn_id.node);
}
ast_map::node_native_item(_, _) {
ret none;
@ -2490,19 +2501,35 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
some(val)
}
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id,
substs: option<([ty::t], typeck::dict_res)>)
-> lval_maybe_callee {
let ccx = bcx_ccx(bcx);
let tys = ty::node_id_to_type_params(ccx.tcx, id);
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
if ccx.sess.opts.monomorphize && vec::len(tys) > 0u &&
if ccx.sess.opts.monomorphize &&
(option::is_some(substs) || vec::len(tys) > 0u) &&
fn_id.crate == ast::local_crate &&
!vec::any(tys, {|t| ty::type_has_params(t)}) &&
vec::all(*tpt.bounds, {|bs| vec::all(*bs, {|b|
alt b { ty::bound_iface(_) { false } _ { true } }
})}) {
let dicts = ccx.dict_map.find(id);
alt monomorphic_fn(ccx, fn_id, tys, dicts) {
!vec::any(tys, {|t| ty::type_has_params(t)}) {
let mono = alt substs {
some((stys, dicts)) {
if (vec::len(stys) + vec::len(stys)) > 0u {
monomorphic_fn(ccx, fn_id, stys + tys, some(dicts))
} else { none }
}
none {
alt ccx.dict_map.find(id) {
some(dicts) {
alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) {
some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) }
none { none }
}
}
none { monomorphic_fn(ccx, fn_id, tys, none) }
}
}
};
alt mono {
some({llfn, fty}) {
ret {bcx: bcx, val: llfn,
kind: owned, env: null_env,
@ -2601,12 +2628,12 @@ fn trans_var(cx: @block_ctxt, def: ast::def, id: ast::node_id)
let ccx = bcx_ccx(cx);
alt def {
ast::def_fn(did, _) {
ret lval_static_fn(cx, did, id);
ret lval_static_fn(cx, did, id, none);
}
ast::def_variant(tid, vid) {
if vec::len(ty::enum_variant_with_id(ccx.tcx, tid, vid).args) > 0u {
// N-ary variant.
ret lval_static_fn(cx, vid, id);
ret lval_static_fn(cx, vid, id, none);
} else {
// Nullary variant.
let enum_ty = ty::node_id_to_type(ccx.tcx, id);
@ -4259,7 +4286,7 @@ fn mk_standard_basic_blocks(llfn: ValueRef) ->
// - trans_args
fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
llfndecl: ValueRef, id: ast::node_id,
param_substs: option<[ty::t]>,
param_substs: option<param_substs>,
sp: option<span>) -> @fn_ctxt {
let llbbs = mk_standard_basic_blocks(llfndecl);
ret @{llfn: llfndecl,
@ -4405,7 +4432,7 @@ enum self_arg { impl_self(ty::t), no_self, }
fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
body: ast::blk, llfndecl: ValueRef,
ty_self: self_arg, ty_params: [ast::ty_param],
param_substs: option<[ty::t]>,
param_substs: option<param_substs>,
id: ast::node_id, maybe_load_env: fn(@fn_ctxt)) {
set_uwtable(llfndecl);
@ -4421,14 +4448,6 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
let block_ty = node_id_type(bcx, body.node.id);
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
alt param_substs {
some(ts) {
arg_tys = vec::map(arg_tys, {|a|
{mode: a.mode,
ty: ty::substitute_type_params(fcx.ccx.tcx, ts, a.ty)}})
}
_ {}
}
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys);
maybe_load_env(fcx);
@ -4454,7 +4473,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
// function.
fn trans_fn(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
body: ast::blk, llfndecl: ValueRef, ty_self: self_arg,
ty_params: [ast::ty_param], param_substs: option<[ty::t]>,
ty_params: [ast::ty_param], param_substs: option<param_substs>,
id: ast::node_id) {
let do_time = ccx.sess.opts.stats;
let start = if do_time { time::get_time() }
@ -4473,7 +4492,7 @@ fn trans_fn(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
ctor_id: ast::node_id, ty_params: [ast::ty_param],
param_substs: option<[ty::t]>, llfndecl: ValueRef) {
param_substs: option<param_substs>, llfndecl: ValueRef) {
// Create a function for the constructor
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id,
param_substs, none);
@ -4505,11 +4524,11 @@ fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
}
fn trans_enum_variant(ccx: @crate_ctxt,
enum_id: ast::node_id,
fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
variant: ast::variant, disr: int, is_degen: bool,
ty_params: [ast::ty_param],
param_substs: option<[ty::t]>, llfndecl: ValueRef) {
param_substs: option<param_substs>,
llfndecl: ValueRef) {
// Translate variant arguments to function arguments.
let fn_args = [], i = 0u;
for varg in variant.node.args {
@ -4522,7 +4541,7 @@ fn trans_enum_variant(ccx: @crate_ctxt,
param_substs, none);
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
let ty_param_substs = alt param_substs {
some(ts) { ts }
some(substs) { substs.tys }
none {
let i = 0u;
vec::map(ty_params, {|tp|

View file

@ -132,6 +132,10 @@ enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
type fn_ty_param = {desc: ValueRef, dicts: option<[ValueRef]>};
type param_substs = {tys: [ty::t],
dicts: option<typeck::dict_res>,
bounds: @[ty::param_bounds]};
// Function context. Every LLVM function we create will have one of
// these.
type fn_ctxt = {
@ -200,7 +204,7 @@ type fn_ctxt = {
// If this function is being monomorphized, this contains the type
// substitutions used.
param_substs: option<[ty::t]>,
param_substs: option<param_substs>,
// The source span and nesting context where this function comes from, for
// error reporting and symbol generation.
@ -901,7 +905,7 @@ fn node_id_type(bcx: @block_ctxt, id: ast::node_id) -> ty::t {
let tcx = bcx_tcx(bcx);
let t = ty::node_id_to_type(tcx, id);
alt bcx.fcx.param_substs {
some(s) { ty::substitute_type_params(tcx, s, t) }
some(substs) { ty::substitute_type_params(tcx, substs.tys, t) }
_ { t }
}
}

View file

@ -76,10 +76,18 @@ fn trans_method_callee(bcx: @block_ctxt, callee_id: ast::node_id,
-> lval_maybe_callee {
alt origin {
typeck::method_static(did) {
trans_static_callee(bcx, callee_id, self, did)
trans_static_callee(bcx, callee_id, self, did, none)
}
typeck::method_param(iid, off, p, b) {
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
alt bcx.fcx.param_substs {
some(substs) {
trans_monomorphized_callee(bcx, callee_id, self,
iid, off, p, b, substs)
}
none {
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
}
}
}
typeck::method_iface(off) {
trans_iface_callee(bcx, callee_id, self, off)
@ -89,10 +97,11 @@ fn trans_method_callee(bcx: @block_ctxt, callee_id: ast::node_id,
// Method callee where the method is statically known
fn trans_static_callee(bcx: @block_ctxt, callee_id: ast::node_id,
base: @ast::expr, did: ast::def_id)
base: @ast::expr, did: ast::def_id,
substs: option<([ty::t], typeck::dict_res)>)
-> lval_maybe_callee {
let {bcx, val} = trans_self_arg(bcx, base);
{env: self_env(val) with lval_static_fn(bcx, did, callee_id)}
{env: self_env(val) with lval_static_fn(bcx, did, callee_id, substs)}
}
fn wrapper_fn_ty(ccx: @crate_ctxt, dict_ty: TypeRef, fty: ty::t,
@ -135,6 +144,38 @@ fn trans_vtable_callee(bcx: @block_ctxt, self: ValueRef, dict: ValueRef,
generic: generic}
}
fn trans_monomorphized_callee(bcx: @block_ctxt, callee_id: ast::node_id,
base: @ast::expr, iface_id: ast::def_id,
n_method: uint, n_param: uint, n_bound: uint,
substs: param_substs) -> lval_maybe_callee {
alt find_dict_in_fn_ctxt(substs, n_param, n_bound) {
typeck::dict_static(impl_did, tys, sub_origins) {
let tcx = bcx_tcx(bcx);
if impl_did.crate != ast::local_crate {
ret trans_param_callee(bcx, callee_id, base, iface_id,
n_method, n_param, n_bound);
}
let mname = ty::iface_methods(tcx, iface_id)[n_method].ident;
let mth = alt tcx.items.get(impl_did.node) {
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
option::get(vec::find(ms, {|m| m.ident == mname}))
}
_ { fail; }
};
ret trans_static_callee(bcx, callee_id, base,
ast_util::local_def(mth.id),
some((tys, sub_origins)));
}
typeck::dict_iface(_) {
ret trans_iface_callee(bcx, callee_id, base, n_method);
}
typeck::dict_param(n_param, n_bound) {
fail "dict_param left in monomorphized function's dict substs";
}
}
}
// Method callee where the dict comes from a type param
fn trans_param_callee(bcx: @block_ctxt, callee_id: ast::node_id,
base: @ast::expr, iface_id: ast::def_id, n_method: uint,
@ -184,6 +225,46 @@ fn trans_vtable(ccx: @crate_ctxt, id: ast::node_id, name: str,
ccx.item_symbols.insert(id, name);
}
fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
-> typeck::dict_origin {
let dict_off = n_bound, i = 0u;
// Dicts are stored in a flat array, finding the right one is
// somewhat awkward
for bounds in *ps.bounds {
i += 1u;
if i >= n_param { break; }
for bound in *bounds {
alt bound { ty::bound_iface(_) { dict_off += 1u; } _ {} }
}
}
option::get(ps.dicts)[dict_off]
}
fn resolve_dicts_in_fn_ctxt(fcx: @fn_ctxt, dicts: typeck::dict_res)
-> option<typeck::dict_res> {
let result = [];
for dict in *dicts {
result += [alt dict {
typeck::dict_static(iid, tys, sub) {
alt resolve_dicts_in_fn_ctxt(fcx, sub) {
some(sub) { typeck::dict_static(iid, tys, sub) }
none { ret none; }
}
}
typeck::dict_param(n_param, n_bound) {
alt fcx.param_substs {
some(substs) {
find_dict_in_fn_ctxt(substs, n_param, n_bound)
}
none { ret none; }
}
}
_ { dict }
}];
}
some(@result)
}
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
fill: fn(ValueRef, @block_ctxt) -> @block_ctxt)
-> ValueRef {

View file

@ -1663,7 +1663,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
if did.crate == ast::local_crate {
alt tcx.items.get(did.node) {
ast_map::node_method(m, _) {
ast_map::node_method(m, _, _) {
let mt = ty_of_method(tcx, m_check, m);
ty::mk_fn(tcx, mt.fty)
}