Fix generation of generic methods with explicit self
There used to be two distinct code paths. Now there is one.
This commit is contained in:
parent
b5411f765c
commit
ce3cc46ce6
4 changed files with 105 additions and 34 deletions
|
@ -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")),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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; }
|
||||
|
|
33
src/test/run-pass/explicit-self-generic.rs
Normal file
33
src/test/run-pass/explicit-self-generic.rs
Normal file
|
@ -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;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue