Skip to content

Commit 1dc5e1a

Browse files
committed
Monomorphize methods and bounded parameters
Issue #1736
1 parent 149d1d4 commit 1dc5e1a

File tree

6 files changed

+143
-39
lines changed

6 files changed

+143
-39
lines changed

src/comp/middle/ast_map.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type path = [path_elt];
1010
enum ast_node {
1111
node_item(@item, @path),
1212
node_native_item(@native_item, @path),
13-
node_method(@method, @path),
13+
node_method(@method, node_id, @path),
1414
node_variant(variant, def_id, @path),
1515
node_expr(@expr),
1616
// 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) {
6969
cx.map.insert(i.id, node_item(i, @cx.path));
7070
alt i.node {
7171
item_impl(_, _, _, ms) {
72-
for m in ms { cx.map.insert(m.id, node_method(m, @cx.path)); }
72+
for m in ms { cx.map.insert(m.id, node_method(m, i.id, @cx.path)); }
7373
}
7474
item_res(_, _, _, dtor_id, ctor_id) {
7575
cx.map.insert(ctor_id, node_res_ctor(i));

src/comp/middle/debuginfo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ fn create_function(fcx: @fn_ctxt) -> @metadata<subprogram_md> {
802802
bound to non-function"); }
803803
}
804804
}
805-
ast_map::node_method(method, _) {
805+
ast_map::node_method(method, _, _) {
806806
(method.ident, method.decl.output, method.id)
807807
}
808808
ast_map::node_res_ctor(item) {

src/comp/middle/trans/base.rs

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,10 +2450,12 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
24502450
some(val) { ret some(val); }
24512451
none {}
24522452
}
2453+
24532454
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
24542455
let mono_ty = ty::substitute_type_params(ccx.tcx, substs, tpt.ty);
24552456
let llfty = type_of_fn_from_ty(ccx, mono_ty, []);
24562457
let lldecl;
2458+
let psubsts = some({tys: substs, dicts: dicts, bounds: tpt.bounds});
24572459
alt ccx.tcx.items.get(fn_id.node) {
24582460
ast_map::node_item(item, pt) {
24592461
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],
24622464
alt item.node {
24632465
ast::item_fn(decl, _, body) {
24642466
trans_fn(ccx, pt, decl, body, lldecl, no_self, [],
2465-
some(substs), fn_id.node);
2467+
psubsts, fn_id.node);
24662468
}
24672469
ast::item_res(decl, _, _, _, ctor_id) {
2468-
trans_res_ctor(ccx, pt, decl, ctor_id, [], some(substs), lldecl);
2470+
trans_res_ctor(ccx, pt, decl, ctor_id, [], psubsts, lldecl);
24692471
}
24702472
_ { fail "Unexpected item type"; }
24712473
}
@@ -2478,7 +2480,16 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
24782480
let this_tv = option::get(vec::find(*tvs, {|tv|
24792481
tv.id.node == fn_id.node}));
24802482
trans_enum_variant(ccx, enum_id.node, v, this_tv.disr_val,
2481-
vec::len(*tvs) == 1u, [], some(substs), lldecl);
2483+
vec::len(*tvs) == 1u, [], psubsts, lldecl);
2484+
}
2485+
ast_map::node_method(mth, impl_id, pt) {
2486+
let pt = *pt + [path_name(mth.ident)];
2487+
let s = mangle_exported_name(ccx, pt, mono_ty);
2488+
lldecl = decl_cdecl_fn(ccx.llmod, s, llfty);
2489+
let selfty = ty::node_id_to_type(ccx.tcx, impl_id);
2490+
let selfty = ty::substitute_type_params(ccx.tcx, substs, selfty);
2491+
trans_fn(ccx, pt, mth.decl, mth.body, lldecl,
2492+
impl_self(selfty), [], psubsts, fn_id.node);
24822493
}
24832494
ast_map::node_native_item(_, _) {
24842495
ret none;
@@ -2490,19 +2501,35 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
24902501
some(val)
24912502
}
24922503

2493-
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id)
2504+
fn lval_static_fn(bcx: @block_ctxt, fn_id: ast::def_id, id: ast::node_id,
2505+
substs: option<([ty::t], typeck::dict_res)>)
24942506
-> lval_maybe_callee {
24952507
let ccx = bcx_ccx(bcx);
24962508
let tys = ty::node_id_to_type_params(ccx.tcx, id);
24972509
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
2498-
if ccx.sess.opts.monomorphize && vec::len(tys) > 0u &&
2510+
if ccx.sess.opts.monomorphize &&
2511+
(option::is_some(substs) || vec::len(tys) > 0u) &&
24992512
fn_id.crate == ast::local_crate &&
2500-
!vec::any(tys, {|t| ty::type_has_params(t)}) &&
2501-
vec::all(*tpt.bounds, {|bs| vec::all(*bs, {|b|
2502-
alt b { ty::bound_iface(_) { false } _ { true } }
2503-
})}) {
2504-
let dicts = ccx.dict_map.find(id);
2505-
alt monomorphic_fn(ccx, fn_id, tys, dicts) {
2513+
!vec::any(tys, {|t| ty::type_has_params(t)}) {
2514+
let mono = alt substs {
2515+
some((stys, dicts)) {
2516+
if (vec::len(stys) + vec::len(stys)) > 0u {
2517+
monomorphic_fn(ccx, fn_id, stys + tys, some(dicts))
2518+
} else { none }
2519+
}
2520+
none {
2521+
alt ccx.dict_map.find(id) {
2522+
some(dicts) {
2523+
alt impl::resolve_dicts_in_fn_ctxt(bcx.fcx, dicts) {
2524+
some(dicts) { monomorphic_fn(ccx, fn_id, tys, some(dicts)) }
2525+
none { none }
2526+
}
2527+
}
2528+
none { monomorphic_fn(ccx, fn_id, tys, none) }
2529+
}
2530+
}
2531+
};
2532+
alt mono {
25062533
some({llfn, fty}) {
25072534
ret {bcx: bcx, val: llfn,
25082535
kind: owned, env: null_env,
@@ -2601,12 +2628,12 @@ fn trans_var(cx: @block_ctxt, def: ast::def, id: ast::node_id)
26012628
let ccx = bcx_ccx(cx);
26022629
alt def {
26032630
ast::def_fn(did, _) {
2604-
ret lval_static_fn(cx, did, id);
2631+
ret lval_static_fn(cx, did, id, none);
26052632
}
26062633
ast::def_variant(tid, vid) {
26072634
if vec::len(ty::enum_variant_with_id(ccx.tcx, tid, vid).args) > 0u {
26082635
// N-ary variant.
2609-
ret lval_static_fn(cx, vid, id);
2636+
ret lval_static_fn(cx, vid, id, none);
26102637
} else {
26112638
// Nullary variant.
26122639
let enum_ty = ty::node_id_to_type(ccx.tcx, id);
@@ -4259,7 +4286,7 @@ fn mk_standard_basic_blocks(llfn: ValueRef) ->
42594286
// - trans_args
42604287
fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
42614288
llfndecl: ValueRef, id: ast::node_id,
4262-
param_substs: option<[ty::t]>,
4289+
param_substs: option<param_substs>,
42634290
sp: option<span>) -> @fn_ctxt {
42644291
let llbbs = mk_standard_basic_blocks(llfndecl);
42654292
ret @{llfn: llfndecl,
@@ -4405,7 +4432,7 @@ enum self_arg { impl_self(ty::t), no_self, }
44054432
fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
44064433
body: ast::blk, llfndecl: ValueRef,
44074434
ty_self: self_arg, ty_params: [ast::ty_param],
4408-
param_substs: option<[ty::t]>,
4435+
param_substs: option<param_substs>,
44094436
id: ast::node_id, maybe_load_env: fn(@fn_ctxt)) {
44104437
set_uwtable(llfndecl);
44114438

@@ -4421,14 +4448,6 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
44214448
let block_ty = node_id_type(bcx, body.node.id);
44224449

44234450
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
4424-
alt param_substs {
4425-
some(ts) {
4426-
arg_tys = vec::map(arg_tys, {|a|
4427-
{mode: a.mode,
4428-
ty: ty::substitute_type_params(fcx.ccx.tcx, ts, a.ty)}})
4429-
}
4430-
_ {}
4431-
}
44324451
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, arg_tys);
44334452

44344453
maybe_load_env(fcx);
@@ -4454,7 +4473,7 @@ fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
44544473
// function.
44554474
fn trans_fn(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
44564475
body: ast::blk, llfndecl: ValueRef, ty_self: self_arg,
4457-
ty_params: [ast::ty_param], param_substs: option<[ty::t]>,
4476+
ty_params: [ast::ty_param], param_substs: option<param_substs>,
44584477
id: ast::node_id) {
44594478
let do_time = ccx.sess.opts.stats;
44604479
let start = if do_time { time::get_time() }
@@ -4473,7 +4492,7 @@ fn trans_fn(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
44734492

44744493
fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
44754494
ctor_id: ast::node_id, ty_params: [ast::ty_param],
4476-
param_substs: option<[ty::t]>, llfndecl: ValueRef) {
4495+
param_substs: option<param_substs>, llfndecl: ValueRef) {
44774496
// Create a function for the constructor
44784497
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id,
44794498
param_substs, none);
@@ -4505,11 +4524,11 @@ fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
45054524
}
45064525

45074526

4508-
fn trans_enum_variant(ccx: @crate_ctxt,
4509-
enum_id: ast::node_id,
4527+
fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
45104528
variant: ast::variant, disr: int, is_degen: bool,
45114529
ty_params: [ast::ty_param],
4512-
param_substs: option<[ty::t]>, llfndecl: ValueRef) {
4530+
param_substs: option<param_substs>,
4531+
llfndecl: ValueRef) {
45134532
// Translate variant arguments to function arguments.
45144533
let fn_args = [], i = 0u;
45154534
for varg in variant.node.args {
@@ -4522,7 +4541,7 @@ fn trans_enum_variant(ccx: @crate_ctxt,
45224541
param_substs, none);
45234542
create_llargs_for_fn_args(fcx, no_self, fn_args, ty_params);
45244543
let ty_param_substs = alt param_substs {
4525-
some(ts) { ts }
4544+
some(substs) { substs.tys }
45264545
none {
45274546
let i = 0u;
45284547
vec::map(ty_params, {|tp|

src/comp/middle/trans/common.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ enum local_val { local_mem(ValueRef), local_imm(ValueRef), }
132132

133133
type fn_ty_param = {desc: ValueRef, dicts: option<[ValueRef]>};
134134

135+
type param_substs = {tys: [ty::t],
136+
dicts: option<typeck::dict_res>,
137+
bounds: @[ty::param_bounds]};
138+
135139
// Function context. Every LLVM function we create will have one of
136140
// these.
137141
type fn_ctxt = {
@@ -200,7 +204,7 @@ type fn_ctxt = {
200204

201205
// If this function is being monomorphized, this contains the type
202206
// substitutions used.
203-
param_substs: option<[ty::t]>,
207+
param_substs: option<param_substs>,
204208

205209
// The source span and nesting context where this function comes from, for
206210
// error reporting and symbol generation.
@@ -901,7 +905,7 @@ fn node_id_type(bcx: @block_ctxt, id: ast::node_id) -> ty::t {
901905
let tcx = bcx_tcx(bcx);
902906
let t = ty::node_id_to_type(tcx, id);
903907
alt bcx.fcx.param_substs {
904-
some(s) { ty::substitute_type_params(tcx, s, t) }
908+
some(substs) { ty::substitute_type_params(tcx, substs.tys, t) }
905909
_ { t }
906910
}
907911
}

src/comp/middle/trans/impl.rs

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,18 @@ fn trans_method_callee(bcx: @block_ctxt, callee_id: ast::node_id,
7676
-> lval_maybe_callee {
7777
alt origin {
7878
typeck::method_static(did) {
79-
trans_static_callee(bcx, callee_id, self, did)
79+
trans_static_callee(bcx, callee_id, self, did, none)
8080
}
8181
typeck::method_param(iid, off, p, b) {
82-
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
82+
alt bcx.fcx.param_substs {
83+
some(substs) {
84+
trans_monomorphized_callee(bcx, callee_id, self,
85+
iid, off, p, b, substs)
86+
}
87+
none {
88+
trans_param_callee(bcx, callee_id, self, iid, off, p, b)
89+
}
90+
}
8391
}
8492
typeck::method_iface(off) {
8593
trans_iface_callee(bcx, callee_id, self, off)
@@ -89,10 +97,11 @@ fn trans_method_callee(bcx: @block_ctxt, callee_id: ast::node_id,
8997

9098
// Method callee where the method is statically known
9199
fn trans_static_callee(bcx: @block_ctxt, callee_id: ast::node_id,
92-
base: @ast::expr, did: ast::def_id)
100+
base: @ast::expr, did: ast::def_id,
101+
substs: option<([ty::t], typeck::dict_res)>)
93102
-> lval_maybe_callee {
94103
let {bcx, val} = trans_self_arg(bcx, base);
95-
{env: self_env(val) with lval_static_fn(bcx, did, callee_id)}
104+
{env: self_env(val) with lval_static_fn(bcx, did, callee_id, substs)}
96105
}
97106

98107
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,
135144
generic: generic}
136145
}
137146

147+
fn trans_monomorphized_callee(bcx: @block_ctxt, callee_id: ast::node_id,
148+
base: @ast::expr, iface_id: ast::def_id,
149+
n_method: uint, n_param: uint, n_bound: uint,
150+
substs: param_substs) -> lval_maybe_callee {
151+
alt find_dict_in_fn_ctxt(substs, n_param, n_bound) {
152+
typeck::dict_static(impl_did, tys, sub_origins) {
153+
let tcx = bcx_tcx(bcx);
154+
if impl_did.crate != ast::local_crate {
155+
ret trans_param_callee(bcx, callee_id, base, iface_id,
156+
n_method, n_param, n_bound);
157+
}
158+
let mname = ty::iface_methods(tcx, iface_id)[n_method].ident;
159+
let mth = alt tcx.items.get(impl_did.node) {
160+
ast_map::node_item(@{node: ast::item_impl(_, _, _, ms), _}, _) {
161+
option::get(vec::find(ms, {|m| m.ident == mname}))
162+
}
163+
_ { fail; }
164+
};
165+
ret trans_static_callee(bcx, callee_id, base,
166+
ast_util::local_def(mth.id),
167+
some((tys, sub_origins)));
168+
}
169+
typeck::dict_iface(_) {
170+
ret trans_iface_callee(bcx, callee_id, base, n_method);
171+
}
172+
typeck::dict_param(n_param, n_bound) {
173+
fail "dict_param left in monomorphized function's dict substs";
174+
}
175+
}
176+
}
177+
178+
138179
// Method callee where the dict comes from a type param
139180
fn trans_param_callee(bcx: @block_ctxt, callee_id: ast::node_id,
140181
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,
184225
ccx.item_symbols.insert(id, name);
185226
}
186227

228+
fn find_dict_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
229+
-> typeck::dict_origin {
230+
let dict_off = n_bound, i = 0u;
231+
// Dicts are stored in a flat array, finding the right one is
232+
// somewhat awkward
233+
for bounds in *ps.bounds {
234+
i += 1u;
235+
if i >= n_param { break; }
236+
for bound in *bounds {
237+
alt bound { ty::bound_iface(_) { dict_off += 1u; } _ {} }
238+
}
239+
}
240+
option::get(ps.dicts)[dict_off]
241+
}
242+
243+
fn resolve_dicts_in_fn_ctxt(fcx: @fn_ctxt, dicts: typeck::dict_res)
244+
-> option<typeck::dict_res> {
245+
let result = [];
246+
for dict in *dicts {
247+
result += [alt dict {
248+
typeck::dict_static(iid, tys, sub) {
249+
alt resolve_dicts_in_fn_ctxt(fcx, sub) {
250+
some(sub) { typeck::dict_static(iid, tys, sub) }
251+
none { ret none; }
252+
}
253+
}
254+
typeck::dict_param(n_param, n_bound) {
255+
alt fcx.param_substs {
256+
some(substs) {
257+
find_dict_in_fn_ctxt(substs, n_param, n_bound)
258+
}
259+
none { ret none; }
260+
}
261+
}
262+
_ { dict }
263+
}];
264+
}
265+
some(@result)
266+
}
267+
187268
fn trans_wrapper(ccx: @crate_ctxt, pt: path, llfty: TypeRef,
188269
fill: fn(ValueRef, @block_ctxt) -> @block_ctxt)
189270
-> ValueRef {

src/comp/middle/typeck.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,7 @@ fn lookup_method_inner(fcx: @fn_ctxt, expr: @ast::expr,
16631663
fn ty_from_did(tcx: ty::ctxt, did: ast::def_id) -> ty::t {
16641664
if did.crate == ast::local_crate {
16651665
alt tcx.items.get(did.node) {
1666-
ast_map::node_method(m, _) {
1666+
ast_map::node_method(m, _, _) {
16671667
let mt = ty_of_method(tcx, m_check, m);
16681668
ty::mk_fn(tcx, mt.fty)
16691669
}

0 commit comments

Comments
 (0)