about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2012-02-09 11:17:11 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2012-02-09 11:58:07 +0100
commit1dc5e1aa94d1c82d12385dfcb95c75cbaaa318a9 (patch)
tree02ef5d7e0c1c936eea24923d398a7acfb763c1e0
parent149d1d4a6e3bb8a439eff78cc6edb25f16aa47c5 (diff)
Monomorphize methods and bounded parameters
Issue #1736
-rw-r--r--src/comp/middle/ast_map.rs4
-rw-r--r--src/comp/middle/debuginfo.rs2
-rw-r--r--src/comp/middle/trans/base.rs77
-rw-r--r--src/comp/middle/trans/common.rs8
-rw-r--r--src/comp/middle/trans/impl.rs89
-rw-r--r--src/comp/middle/typeck.rs2
6 files changed, 143 insertions, 39 deletions
diff --git a/src/comp/middle/ast_map.rs b/src/comp/middle/ast_map.rs
index 423b6ab218d..5973be0cbd7 100644
--- a/src/comp/middle/ast_map.rs
+++ b/src/comp/middle/ast_map.rs
@@ -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));
diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs
index 49304b6bd27..bb38a101207 100644
--- a/src/comp/middle/debuginfo.rs
+++ b/src/comp/middle/debuginfo.rs
@@ -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) {
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index ae90d2b8ced..f8accd50714 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<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|
diff --git a/src/comp/middle/trans/common.rs b/src/comp/middle/trans/common.rs
index fdac4fa165f..e714dca039c 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<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 }
     }
 }
diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs
index 1e66e3e9044..2de21f8fb2e 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<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 {
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 7eb9380d3f8..a26ef788abd 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)
               }