diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs index 423b6ab218dd..5973be0cbd7b 100644 --- a/src/comp/middle/ast_map.rs +++ b/src/comp/middle/ast_map.rs @@ -10,7 +10,7 @@ enum path_elt { path_mod(str), path_name(str) } 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)); diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs index 49304b6bd273..bb38a1012072 100644 --- a/src/comp/middle/debuginfo.rs +++ b/src/comp/middle/debuginfo.rs @@ -802,7 +802,7 @@ fn create_function(fcx: @fn_ctxt) -> @metadata { 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) { diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs index ae90d2b8cedd..f8accd50714f 100644 --- a/src/comp/middle/trans/base.rs +++ b/src/comp/middle/trans/base.rs @@ -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, sp: option) -> @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, 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, 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, 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, + 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| diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs index fdac4fa165fc..e714dca039cf 100644 --- a/src/comp/middle/trans/common.rs +++ b/src/comp/middle/trans/common.rs @@ -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, + bounds: @[ty::param_bounds]}; + // Function context. Every LLVM function we create will have one of // these. type fn_ctxt = { @@ -200,7 +204,7 @@ enum local_val { local_mem(ValueRef), local_imm(ValueRef), } // If this function is being monomorphized, this contains the type // substitutions used. - param_substs: option<[ty::t]>, + param_substs: option, // 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 } } } diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs index 1e66e3e9044f..2de21f8fb2e7 100644 --- a/src/comp/middle/trans/impl.rs +++ b/src/comp/middle/trans/impl.rs @@ -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 { + 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 { diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 7eb9380d3f8f..a26ef788abd8 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -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) }