about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-08-21 19:51:43 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-08-21 20:15:22 -0700
commitce3cc46ce602990b39f76344a2132b2c2db122dd (patch)
treec62f4856a3e2054fc8719a8754245d4e321d53b9 /src
parentb5411f765cdac796fc6798e49521c8da89a394cc (diff)
Fix generation of generic methods with explicit self
There used to be two distinct code paths.  Now there is one.
Diffstat (limited to 'src')
-rw-r--r--src/rustc/middle/trans/base.rs11
-rw-r--r--src/rustc/middle/trans/impl.rs93
-rw-r--r--src/rustc/middle/ty.rs2
-rw-r--r--src/test/run-pass/explicit-self-generic.rs33
4 files changed, 105 insertions, 34 deletions
diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs
index cf813d108ea..1def54d5ebf 100644
--- a/src/rustc/middle/trans/base.rs
+++ b/src/rustc/middle/trans/base.rs
@@ -2246,10 +2246,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id,
       ast_map::node_method(mth, impl_def_id, _) => {
         let d = mk_lldecl();
         set_inline_hint_if_appr(mth.attrs, d);
-        let selfty = ty::node_id_to_type(ccx.tcx, mth.self_id);
-        let selfty = ty::subst_tps(ccx.tcx, substs, selfty);
-        trans_fn(ccx, pt, mth.decl, mth.body, d,
-                 impl_self(selfty), psubsts, fn_id.node);
+        impl::trans_method(ccx, pt, mth, psubsts, d);
         d
       }
       ast_map::node_ctor(nm, tps, ctor, parent_id, _) => {
@@ -5321,13 +5318,13 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
               }
               ast::provided(m) => {
                 exprt = true;
-                trans_method(ccx, id, pth, m)
+                register_method(ccx, id, pth, m)
               }
             }
           }
           ast_map::node_method(m, _, pth) => {
             exprt = true;
-            trans_method(ccx, id, pth, m)
+            register_method(ccx, id, pth, m)
           }
           ast_map::node_foreign_item(ni, _, pth) => {
             exprt = true;
@@ -5397,7 +5394,7 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
     }
 }
 
-fn trans_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
+fn register_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
                 m: @ast::method) -> ValueRef {
     let mty = ty::node_id_to_type(ccx.tcx, id);
     let pth = vec::append(*pth, ~[path_name(@ccx.names(~"meth")),
diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs
index 07923695183..e85cef79358 100644
--- a/src/rustc/middle/trans/impl.rs
+++ b/src/rustc/middle/trans/impl.rs
@@ -18,41 +18,82 @@ import util::ppaux::{ty_to_str, tys_to_str};
 
 import syntax::print::pprust::expr_to_str;
 
+/**
+The main "translation" pass for methods.  Generates code
+for non-monomorphized methods only.  Other methods will
+be generated once they are invoked with specific type parameters,
+see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
+*/
 fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
               methods: ~[@ast::method], tps: ~[ast::ty_param]) {
     let _icx = ccx.insn_ctxt("impl::trans_impl");
     if tps.len() > 0u { return; }
     let sub_path = vec::append_one(path, path_name(name));
-    for vec::each(methods) |m| {
-        if m.tps.len() == 0u {
-            let llfn = get_item_val(ccx, m.id);
-            let self_ty = ty::node_id_to_type(ccx.tcx, m.self_id);
-            let self_arg = match m.self_ty.node {
-              ast::sty_static => { no_self }
-              ast::sty_box(_) => {
-                impl_self(ty::mk_imm_box(ccx.tcx, self_ty))
-              }
-              ast::sty_uniq(_) => {
-                impl_self(ty::mk_imm_uniq(ccx.tcx, self_ty))
-              }
-              ast::sty_region(*) => {
-                impl_self(ty::mk_imm_ptr(ccx.tcx, self_ty))
-              }
-              ast::sty_value => {
-                impl_owned_self(self_ty)
-              }
-              ast::sty_by_ref => { impl_self(self_ty) }
-            };
-
-            trans_fn(ccx,
-                     vec::append_one(sub_path, path_name(m.ident)),
-                     m.decl, m.body,
-                     llfn, self_arg,
-                     none, m.id);
+    for vec::each(methods) |method| {
+        if method.tps.len() == 0u {
+            let llfn = get_item_val(ccx, method.id);
+            let path = vec::append_one(sub_path, path_name(method.ident));
+            trans_method(ccx, path, method, none, llfn);
         }
     }
 }
 
+/**
+Translates a (possibly monomorphized) method body.
+
+# Parameters
+
+- `path`: the path to the method
+- `method`: the AST node for the method
+- `param_substs`: if this is a generic method, the current values for
+  type parameters and so forth, else none
+- `llfn`: the LLVM ValueRef for the method
+*/
+fn trans_method(ccx: @crate_ctxt,
+                path: path,
+                method: &ast::method,
+                param_substs: option<param_substs>,
+                llfn: ValueRef) {
+    // determine the (monomorphized) type that `self` maps to for this method
+    let self_ty = ty::node_id_to_type(ccx.tcx, method.self_id);
+    let self_ty = match param_substs {
+      none => self_ty,
+      some({tys: ref tys, _}) => ty::subst_tps(ccx.tcx, *tys, self_ty)
+    };
+
+    // apply any transformations from the explicit self declaration
+    let self_arg = match method.self_ty.node {
+      ast::sty_static => {
+        no_self
+      }
+      ast::sty_box(_) => {
+        impl_self(ty::mk_imm_box(ccx.tcx, self_ty))
+      }
+      ast::sty_uniq(_) => {
+        impl_self(ty::mk_imm_uniq(ccx.tcx, self_ty))
+      }
+      ast::sty_region(*) => {
+        impl_self(ty::mk_imm_ptr(ccx.tcx, self_ty))
+      }
+      ast::sty_value => {
+        impl_owned_self(self_ty)
+      }
+      ast::sty_by_ref => {
+        impl_self(self_ty)
+      }
+    };
+
+    // generate the actual code
+    trans_fn(ccx,
+             path,
+             method.decl,
+             method.body,
+             llfn,
+             self_arg,
+             param_substs,
+             method.id);
+}
+
 fn trans_self_arg(bcx: block, base: @ast::expr,
                   mentry: typeck::method_map_entry) -> result {
     let _icx = bcx.insn_ctxt("impl::trans_self_arg");
diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs
index e59a29cfec2..b0f8746d162 100644
--- a/src/rustc/middle/ty.rs
+++ b/src/rustc/middle/ty.rs
@@ -1106,7 +1106,7 @@ fn fold_region(cx: ctxt, t0: t, fldop: fn(region, bool) -> region) -> t {
 }
 
 // Substitute *only* type parameters.  Used in trans where regions are erased.
-fn subst_tps(cx: ctxt, tps: ~[t], typ: t) -> t {
+fn subst_tps(cx: ctxt, tps: &[t], typ: t) -> t {
     if tps.len() == 0u { return typ; }
     let tb = ty::get(typ);
     if !tbox_has_flag(tb, has_params) { return typ; }
diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs
new file mode 100644
index 00000000000..5b6ed42e228
--- /dev/null
+++ b/src/test/run-pass/explicit-self-generic.rs
@@ -0,0 +1,33 @@
+use std;
+
+/**
+ * A function that returns a hash of a value
+ *
+ * The hash should concentrate entropy in the lower bits.
+ */
+type HashFn<K> = pure fn~(K) -> uint;
+type EqFn<K> = pure fn~(K, K) -> bool;
+
+enum LinearMap<K,V> {
+    LinearMap_({
+        resize_at: uint,
+        size: uint})
+}
+
+fn linear_map<K,V>() -> LinearMap<K,V> {
+    LinearMap_({
+        resize_at: 32,
+        size: 0})
+}
+
+impl<K,V> LinearMap<K,V> {
+    fn len(&mut self) -> uint {
+        self.size
+    }
+}
+
+fn main() {
+    let mut m = ~linear_map::<(),()>();
+    assert m.len() == 0;
+}
+