diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index cf813d108ea96a9d3cef7f1b567f86f68c21617f..1def54d5ebf874a7de8c15994f1767716232b1f2 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 07923695183ec7b3fefc3d58662e32a310790b74..e85cef79358dd3e0d8cf60f91e55510b268f37d8 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -18,41 +18,82 @@ 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, + 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 e59a29cfec28bd1de53f2d4eb11d48be1a3e686b..b0f8746d1628089ff6fc320c395cf0489d51fc0c 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -1106,7 +1106,7 @@ fn do_fold(cx: ctxt, t0: t, under_r: bool, } // 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 0000000000000000000000000000000000000000..5b6ed42e2288cd822f6c88852b885814f3d3b96e --- /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 = pure fn~(K) -> uint; +type EqFn = pure fn~(K, K) -> bool; + +enum LinearMap { + LinearMap_({ + resize_at: uint, + size: uint}) +} + +fn linear_map() -> LinearMap { + LinearMap_({ + resize_at: 32, + size: 0}) +} + +impl LinearMap { + fn len(&mut self) -> uint { + self.size + } +} + +fn main() { + let mut m = ~linear_map::<(),()>(); + assert m.len() == 0; +} +