first steps to autoderef on method calls
This commit is contained in:
parent
6c056fba4d
commit
6e73e45e37
12 changed files with 198 additions and 118 deletions
|
|
@ -20,9 +20,9 @@ import std::serialization::deserializer_helpers;
|
|||
import std::prettyprint::serializer;
|
||||
import std::smallintmap::map;
|
||||
import middle::{ty, typeck};
|
||||
import middle::typeck::{method_origin,
|
||||
serialize_method_origin,
|
||||
deserialize_method_origin,
|
||||
import middle::typeck::{method_origin, method_map_entry,
|
||||
serialize_method_map_entry,
|
||||
deserialize_method_map_entry,
|
||||
vtable_res,
|
||||
vtable_origin};
|
||||
import driver::session::session;
|
||||
|
|
@ -546,16 +546,12 @@ impl of tr for freevar_entry {
|
|||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
// Encoding and decoding of method_origin
|
||||
|
||||
fn encode_method_origin(ebml_w: ebml::writer, mo: method_origin) {
|
||||
serialize_method_origin(ebml_w, mo)
|
||||
}
|
||||
// Encoding and decoding of method_map_entry
|
||||
|
||||
impl helper for ebml::ebml_deserializer {
|
||||
fn read_method_origin(xcx: extended_decode_ctxt) -> method_origin {
|
||||
let fv = deserialize_method_origin(self);
|
||||
fv.tr(xcx)
|
||||
fn read_method_map_entry(xcx: extended_decode_ctxt) -> method_map_entry {
|
||||
let mme = deserialize_method_map_entry(self);
|
||||
{derefs: mme.derefs, origin: mme.origin.tr(xcx)}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -565,8 +561,8 @@ impl of tr for method_origin {
|
|||
typeck::method_static(did) {
|
||||
typeck::method_static(did.tr(xcx))
|
||||
}
|
||||
typeck::method_param(did, m, p, b) {
|
||||
typeck::method_param(did.tr(xcx), m, p, b)
|
||||
typeck::method_param(mp) {
|
||||
typeck::method_param({iface_id:mp.iface_id.tr(xcx) with mp})
|
||||
}
|
||||
typeck::method_iface(did, m) {
|
||||
typeck::method_iface(did.tr(xcx), m)
|
||||
|
|
@ -860,11 +856,11 @@ fn encode_side_tables_for_id(ecx: @e::encode_ctxt,
|
|||
// impl_map is not used except when emitting metadata,
|
||||
// don't need to keep it.
|
||||
|
||||
option::iter(maps.method_map.find(id)) {|mo|
|
||||
option::iter(maps.method_map.find(id)) {|mme|
|
||||
ebml_w.tag(c::tag_table_method_map) {||
|
||||
ebml_w.id(id);
|
||||
ebml_w.tag(c::tag_table_val) {||
|
||||
serialize_method_origin(ebml_w, mo)
|
||||
serialize_method_map_entry(ebml_w, mme)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -983,8 +979,9 @@ fn decode_side_tables(xcx: extended_decode_ctxt,
|
|||
let dvec = @dvec::from_vec(vec::to_mut(ids));
|
||||
dcx.maps.last_use_map.insert(id, dvec);
|
||||
} else if tag == (c::tag_table_method_map as uint) {
|
||||
dcx.maps.method_map.insert(id,
|
||||
val_dsr.read_method_origin(xcx));
|
||||
dcx.maps.method_map.insert(
|
||||
id,
|
||||
val_dsr.read_method_map_entry(xcx));
|
||||
} else if tag == (c::tag_table_vtable_map as uint) {
|
||||
dcx.maps.vtable_map.insert(id,
|
||||
val_dsr.read_vtable_res(xcx));
|
||||
|
|
|
|||
|
|
@ -261,14 +261,15 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
|
|||
ty::lookup_item_type(cx.tcx, did).bounds
|
||||
}
|
||||
expr_field(base, _, _) {
|
||||
alt cx.method_map.get(e.id) {
|
||||
alt cx.method_map.get(e.id).origin {
|
||||
typeck::method_static(did) {
|
||||
// n.b.: When we encode class/impl methods, the bounds
|
||||
// that we encode include both the class/impl bounds
|
||||
// and then the method bounds themselves...
|
||||
ty::lookup_item_type(cx.tcx, did).bounds
|
||||
}
|
||||
typeck::method_param(ifce_id, n_mth, _, _) |
|
||||
typeck::method_param({iface_id:ifce_id,
|
||||
method_num:n_mth, _}) |
|
||||
typeck::method_iface(ifce_id, n_mth) {
|
||||
// ...iface methods bounds, in contrast, include only the
|
||||
// method bounds, so we must preprend the tps from the
|
||||
|
|
|
|||
|
|
@ -1517,13 +1517,13 @@ fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr,
|
|||
let _icx = bcx.insn_ctxt("trans_unary");
|
||||
// Check for user-defined method call
|
||||
alt bcx.ccx().maps.method_map.find(un_expr.id) {
|
||||
some(origin) {
|
||||
some(mentry) {
|
||||
let callee_id = ast_util::op_expr_callee_id(un_expr);
|
||||
let fty = node_id_type(bcx, callee_id);
|
||||
ret trans_call_inner(
|
||||
bcx, un_expr.info(), fty,
|
||||
expr_ty(bcx, un_expr),
|
||||
{|bcx| impl::trans_method_callee(bcx, callee_id, e, origin) },
|
||||
{|bcx| impl::trans_method_callee(bcx, callee_id, e, mentry) },
|
||||
arg_exprs([]), dest);
|
||||
}
|
||||
_ {}
|
||||
|
|
@ -1814,14 +1814,17 @@ fn root_value(bcx: block, val: ValueRef, ty: ty::t,
|
|||
add_root_cleanup(bcx, scope_id, root_loc, ty);
|
||||
}
|
||||
|
||||
// autoderefs the value `v`, either as many times as we can (if `max ==
|
||||
// uint::max_value`) or `max` times.
|
||||
fn autoderef(cx: block, e_id: ast::node_id,
|
||||
v: ValueRef, t: ty::t) -> result_t {
|
||||
v: ValueRef, t: ty::t,
|
||||
max: uint) -> result_t {
|
||||
let _icx = cx.insn_ctxt("autoderef");
|
||||
let mut v1: ValueRef = v;
|
||||
let mut t1: ty::t = t;
|
||||
let ccx = cx.ccx();
|
||||
let mut derefs = 0u;
|
||||
loop {
|
||||
while derefs < max {
|
||||
#debug["autoderef(e_id=%d, v1=%s, t1=%s, derefs=%u)",
|
||||
e_id, val_str(ccx.tn, v1), ty_to_str(ccx.tcx, t1),
|
||||
derefs];
|
||||
|
|
@ -1872,6 +1875,11 @@ fn autoderef(cx: block, e_id: ast::node_id,
|
|||
}
|
||||
v1 = load_if_immediate(cx, v1, t1);
|
||||
}
|
||||
|
||||
// either we were asked to deref a specific number of times, in which case
|
||||
// we should have, or we asked to deref as many times as we can
|
||||
assert derefs == max || max == uint::max_value;
|
||||
|
||||
ret {bcx: cx, val: v1, ty: t1};
|
||||
}
|
||||
|
||||
|
|
@ -2572,7 +2580,9 @@ fn trans_rec_field(bcx: block, base: @ast::expr,
|
|||
field: ast::ident) -> lval_result {
|
||||
let _icx = bcx.insn_ctxt("trans_rec_field");
|
||||
let {bcx, val} = trans_temp_expr(bcx, base);
|
||||
let {bcx, val, ty} = autoderef(bcx, base.id, val, expr_ty(bcx, base));
|
||||
let {bcx, val, ty} =
|
||||
autoderef(bcx, base.id, val, expr_ty(bcx, base),
|
||||
uint::max_value);
|
||||
trans_rec_field_inner(bcx, val, ty, field, base.span)
|
||||
}
|
||||
|
||||
|
|
@ -2611,7 +2621,7 @@ fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
|
|||
let _icx = cx.insn_ctxt("trans_index");
|
||||
let base_ty = expr_ty(cx, base);
|
||||
let exp = trans_temp_expr(cx, base);
|
||||
let lv = autoderef(exp.bcx, base.id, exp.val, base_ty);
|
||||
let lv = autoderef(exp.bcx, base.id, exp.val, base_ty, uint::max_value);
|
||||
let ix = trans_temp_expr(lv.bcx, idx);
|
||||
let v = lv.val;
|
||||
let bcx = ix.bcx;
|
||||
|
|
@ -2921,13 +2931,16 @@ fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
|
|||
// temp_cleanups: cleanups that should run only if failure occurs before the
|
||||
// call takes place:
|
||||
fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
||||
&temp_cleanups: [ValueRef], ret_flag: option<ValueRef>)
|
||||
&temp_cleanups: [ValueRef], ret_flag: option<ValueRef>,
|
||||
derefs: uint)
|
||||
-> result {
|
||||
#debug("+++ trans_arg_expr on %s", expr_to_str(e));
|
||||
let _icx = cx.insn_ctxt("trans_arg_expr");
|
||||
let ccx = cx.ccx();
|
||||
let e_ty = expr_ty(cx, e);
|
||||
let is_bot = ty::type_is_bot(e_ty);
|
||||
|
||||
// translate the arg expr as an lvalue
|
||||
let lv = alt ret_flag {
|
||||
// If there is a ret_flag, this *must* be a loop body
|
||||
some(ptr) {
|
||||
|
|
@ -2939,13 +2952,32 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
|||
}
|
||||
}
|
||||
}
|
||||
none { trans_temp_lval(cx, e) }
|
||||
none {
|
||||
trans_temp_lval(cx, e)
|
||||
}
|
||||
};
|
||||
|
||||
// auto-deref value as required (this only applies to method
|
||||
// call receivers) of method
|
||||
#debug(" pre-deref value: %s", val_str(lv.bcx.ccx().tn, lv.val));
|
||||
let {lv, e_ty} = if derefs == 0u {
|
||||
{lv: lv, e_ty: e_ty}
|
||||
} else {
|
||||
let {bcx, val} = lval_result_to_result(lv, e_ty);
|
||||
let {bcx, val, ty: e_ty} =
|
||||
autoderef(bcx, e.id, val, e_ty, derefs);
|
||||
{lv: {bcx: bcx, val: val, kind: temporary},
|
||||
e_ty: e_ty}
|
||||
};
|
||||
|
||||
// borrow value (convert from @T to &T and so forth)
|
||||
#debug(" pre-adaptation value: %s", val_str(lv.bcx.ccx().tn, lv.val));
|
||||
let {lv, arg} = adapt_borrowed_value(lv, arg, e);
|
||||
let {lv, ty: e_ty} = adapt_borrowed_value(lv, e, e_ty);
|
||||
let mut bcx = lv.bcx;
|
||||
let mut val = lv.val;
|
||||
#debug(" adapted value: %s", val_str(bcx.ccx().tn, val));
|
||||
|
||||
// finally, deal with the various modes
|
||||
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
|
||||
if is_bot {
|
||||
// For values of type _|_, we generate an
|
||||
|
|
@ -2953,56 +2985,56 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
|||
// be inspected. It's important for the value
|
||||
// to have type lldestty (the callee's expected type).
|
||||
val = llvm::LLVMGetUndef(lldestty);
|
||||
} else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
|
||||
let imm = ty::type_is_immediate(arg.ty);
|
||||
#debug[" arg.ty=%s, imm=%b, arg_mode=%?, lv.kind=%?",
|
||||
ty_to_str(bcx.tcx(), arg.ty), imm, arg_mode, lv.kind];
|
||||
if arg_mode == ast::by_ref && lv.kind != owned && imm {
|
||||
val = do_spill_noroot(bcx, val);
|
||||
}
|
||||
if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
|
||||
val = Load(bcx, val);
|
||||
}
|
||||
} else if arg_mode == ast::by_copy || arg_mode == ast::by_move {
|
||||
let alloc = alloc_ty(bcx, arg.ty);
|
||||
let move_out = arg_mode == ast::by_move ||
|
||||
ccx.maps.last_use_map.contains_key(e.id);
|
||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
||||
memmove_ty(bcx, alloc, val, arg.ty);
|
||||
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
||||
bcx = zero_mem(bcx, val, arg.ty);
|
||||
} else {
|
||||
alt arg_mode {
|
||||
ast::by_ref | ast::by_mutbl_ref {
|
||||
// Ensure that the value is spilled into memory:
|
||||
if lv.kind != owned && ty::type_is_immediate(e_ty) {
|
||||
val = do_spill_noroot(bcx, val);
|
||||
}
|
||||
} else { Store(bcx, val, alloc); }
|
||||
val = alloc;
|
||||
if lv.kind != temporary && !move_out {
|
||||
bcx = take_ty(bcx, val, arg.ty);
|
||||
}
|
||||
}
|
||||
|
||||
// In the event that failure occurs before the call actually
|
||||
// happens, have to cleanup this copy:
|
||||
add_clean_temp_mem(bcx, val, arg.ty);
|
||||
temp_cleanups += [val];
|
||||
} else if ty::type_is_immediate(arg.ty) && lv.kind != owned {
|
||||
val = do_spill(bcx, val, arg.ty);
|
||||
ast::by_val {
|
||||
// Ensure that the value is not spilled into memory:
|
||||
if lv.kind == owned || !ty::type_is_immediate(e_ty) {
|
||||
val = Load(bcx, val);
|
||||
}
|
||||
}
|
||||
|
||||
ast::by_copy | ast::by_move {
|
||||
// Ensure that an owned copy of the value is in memory:
|
||||
let alloc = alloc_ty(bcx, arg.ty);
|
||||
let move_out = arg_mode == ast::by_move ||
|
||||
ccx.maps.last_use_map.contains_key(e.id);
|
||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
||||
memmove_ty(bcx, alloc, val, arg.ty);
|
||||
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
||||
bcx = zero_mem(bcx, val, arg.ty);
|
||||
}
|
||||
} else { Store(bcx, val, alloc); }
|
||||
val = alloc;
|
||||
if lv.kind != temporary && !move_out {
|
||||
bcx = take_ty(bcx, val, arg.ty);
|
||||
}
|
||||
|
||||
// In the event that failure occurs before the call actually
|
||||
// happens, have to cleanup this copy:
|
||||
add_clean_temp_mem(bcx, val, arg.ty);
|
||||
temp_cleanups += [val];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !is_bot && arg.ty != e_ty || ty::type_has_params(arg.ty) {
|
||||
#debug(" casting from %s", val_str(bcx.ccx().tn, val));
|
||||
val = PointerCast(bcx, val, lldestty);
|
||||
}
|
||||
|
||||
#debug("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val));
|
||||
ret rslt(bcx, val);
|
||||
}
|
||||
|
||||
fn load_value_from_lval_result(lv: lval_result) -> ValueRef {
|
||||
alt lv.kind {
|
||||
temporary { lv.val }
|
||||
owned { Load(lv.bcx, lv.val) }
|
||||
owned_imm { lv.val }
|
||||
}
|
||||
}
|
||||
|
||||
// when invoking a method, an argument of type @T or ~T can be implicltly
|
||||
// converted to an argument of type &T. Similarly, [T] can be converted to
|
||||
// [T]/& and so on. If such a conversion (called borrowing) is necessary,
|
||||
|
|
@ -3010,22 +3042,21 @@ fn load_value_from_lval_result(lv: lval_result) -> ValueRef {
|
|||
// routine consults this table and performs these adaptations. It returns a
|
||||
// new location for the borrowed result as well as a new type for the argument
|
||||
// that reflects the borrowed value and not the original.
|
||||
fn adapt_borrowed_value(lv: lval_result, arg: ty::arg,
|
||||
e: @ast::expr) -> {lv: lval_result,
|
||||
arg: ty::arg} {
|
||||
fn adapt_borrowed_value(lv: lval_result,
|
||||
e: @ast::expr,
|
||||
e_ty: ty::t) -> {lv: lval_result,
|
||||
ty: ty::t} {
|
||||
let bcx = lv.bcx;
|
||||
if !expr_is_borrowed(bcx, e) {
|
||||
ret {lv:lv, arg:arg};
|
||||
ret {lv:lv, ty:e_ty};
|
||||
}
|
||||
|
||||
let e_ty = expr_ty(bcx, e);
|
||||
alt ty::get(e_ty).struct {
|
||||
ty::ty_uniq(mt) | ty::ty_box(mt) {
|
||||
let box_ptr = load_value_from_lval_result(lv);
|
||||
let box_ptr = load_value_from_lval_result(lv, e_ty);
|
||||
let body_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_body]);
|
||||
let rptr_ty = ty::mk_rptr(bcx.tcx(), ty::re_static, mt);
|
||||
ret {lv: lval_temp(bcx, body_ptr),
|
||||
arg: {ty: rptr_ty with arg}};
|
||||
ret {lv: lval_temp(bcx, body_ptr), ty: rptr_ty};
|
||||
}
|
||||
|
||||
ty::ty_str | ty::ty_vec(_) |
|
||||
|
|
@ -3057,8 +3088,7 @@ fn adapt_borrowed_value(lv: lval_result, arg: ty::arg,
|
|||
{ty: unit_ty, mutbl: ast::m_imm},
|
||||
ty::vstore_slice(ty::re_static));
|
||||
|
||||
ret {lv: lval_temp(bcx, p),
|
||||
arg: {ty: slice_ty with arg}};
|
||||
ret {lv: lval_temp(bcx, p), ty: slice_ty};
|
||||
}
|
||||
|
||||
_ {
|
||||
|
|
@ -3120,7 +3150,7 @@ fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
|
|||
vec::iteri(es) {|i, e|
|
||||
let r = trans_arg_expr(bcx, arg_tys[i], llarg_tys[i],
|
||||
e, temp_cleanups, if i == last { ret_flag }
|
||||
else { none });
|
||||
else { none }, 0u);
|
||||
bcx = r.bcx;
|
||||
llargs += [r.val];
|
||||
}
|
||||
|
|
@ -3494,11 +3524,20 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
|
|||
// expressions that must 'end up somewhere' (or get ignored).
|
||||
fn trans_temp_expr(bcx: block, e: @ast::expr) -> result {
|
||||
let _icx = bcx.insn_ctxt("trans_temp_expr");
|
||||
let mut {bcx, val, kind} = trans_temp_lval(bcx, e);
|
||||
if kind == owned {
|
||||
val = load_if_immediate(bcx, val, expr_ty(bcx, e));
|
||||
lval_result_to_result(trans_temp_lval(bcx, e), expr_ty(bcx, e))
|
||||
}
|
||||
|
||||
fn load_value_from_lval_result(lv: lval_result, ty: ty::t) -> ValueRef {
|
||||
alt lv.kind {
|
||||
temporary { lv.val }
|
||||
owned { load_if_immediate(lv.bcx, lv.val, ty) }
|
||||
owned_imm { lv.val }
|
||||
}
|
||||
ret {bcx: bcx, val: val};
|
||||
}
|
||||
|
||||
fn lval_result_to_result(lv: lval_result, ty: ty::t) -> result {
|
||||
let val = load_value_from_lval_result(lv, ty);
|
||||
{bcx: lv.bcx, val: val}
|
||||
}
|
||||
|
||||
// Arranges for the value found in `*root_loc` to be dropped once the scope
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ fn trans_impl(ccx: @crate_ctxt, path: path, name: ast::ident,
|
|||
}
|
||||
}
|
||||
|
||||
fn trans_self_arg(bcx: block, base: @ast::expr) -> result {
|
||||
fn trans_self_arg(bcx: block, base: @ast::expr, derefs: uint) -> result {
|
||||
let _icx = bcx.insn_ctxt("impl::trans_self_arg");
|
||||
let basety = expr_ty(bcx, base);
|
||||
let m_by_ref = ast::expl(ast::by_ref);
|
||||
let mut temp_cleanups = [];
|
||||
let result = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
|
||||
T_ptr(type_of::type_of(bcx.ccx(), basety)),
|
||||
base, temp_cleanups, none);
|
||||
base, temp_cleanups, none, derefs);
|
||||
|
||||
// by-ref self argument should not require cleanup in the case of
|
||||
// other arguments failing:
|
||||
|
|
@ -47,19 +47,20 @@ fn trans_self_arg(bcx: block, base: @ast::expr) -> result {
|
|||
}
|
||||
|
||||
fn trans_method_callee(bcx: block, callee_id: ast::node_id,
|
||||
self: @ast::expr, origin: typeck::method_origin)
|
||||
self: @ast::expr, mentry: typeck::method_map_entry)
|
||||
-> lval_maybe_callee {
|
||||
let _icx = bcx.insn_ctxt("impl::trans_method_callee");
|
||||
alt origin {
|
||||
alt mentry.origin {
|
||||
typeck::method_static(did) {
|
||||
let {bcx, val} = trans_self_arg(bcx, self);
|
||||
let {bcx, val} = trans_self_arg(bcx, self, mentry.derefs);
|
||||
{env: self_env(val, node_id_type(bcx, self.id), none)
|
||||
with lval_static_fn(bcx, did, callee_id)}
|
||||
}
|
||||
typeck::method_param(iid, off, p, b) {
|
||||
typeck::method_param({iface_id:iid, method_num:off,
|
||||
param_num:p, bound_num:b}) {
|
||||
alt check bcx.fcx.param_substs {
|
||||
some(substs) {
|
||||
trans_monomorphized_callee(bcx, callee_id, self,
|
||||
trans_monomorphized_callee(bcx, callee_id, self, mentry.derefs,
|
||||
iid, off, p, b, substs)
|
||||
}
|
||||
}
|
||||
|
|
@ -107,8 +108,9 @@ fn method_ty_param_count(ccx: @crate_ctxt, m_id: ast::def_id,
|
|||
}
|
||||
|
||||
fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
|
||||
base: @ast::expr, iface_id: ast::def_id,
|
||||
n_method: uint, n_param: uint, n_bound: uint,
|
||||
base: @ast::expr, derefs: uint,
|
||||
iface_id: ast::def_id, n_method: uint,
|
||||
n_param: uint, n_bound: uint,
|
||||
substs: param_substs) -> lval_maybe_callee {
|
||||
let _icx = bcx.insn_ctxt("impl::trans_monomorphized_callee");
|
||||
alt find_vtable_in_fn_ctxt(substs, n_param, n_bound) {
|
||||
|
|
@ -120,7 +122,7 @@ fn trans_monomorphized_callee(bcx: block, callee_id: ast::node_id,
|
|||
let node_substs = node_id_type_params(bcx, callee_id);
|
||||
let ty_substs = impl_substs +
|
||||
vec::tailn(node_substs, node_substs.len() - n_m_tps);
|
||||
let {bcx, val} = trans_self_arg(bcx, base);
|
||||
let {bcx, val} = trans_self_arg(bcx, base, derefs);
|
||||
let lval = lval_static_fn_inner(bcx, mth_id, callee_id, ty_substs,
|
||||
some(sub_origins));
|
||||
{env: self_env(val, node_id_type(bcx, base.id), none),
|
||||
|
|
|
|||
|
|
@ -180,7 +180,9 @@ fn traverse_inline_body(cx: ctx, body: blk) {
|
|||
}
|
||||
expr_field(_, _, _) {
|
||||
alt cx.method_map.find(e.id) {
|
||||
some(typeck::method_static(did)) { traverse_def_id(cx, did); }
|
||||
some({origin: typeck::method_static(did), _}) {
|
||||
traverse_def_id(cx, did);
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ import driver::session::session;
|
|||
import lib::llvm::{ValueRef, TypeRef};
|
||||
import back::abi;
|
||||
import base::{call_memmove,
|
||||
INIT, copy_val, load_if_immediate, get_tydesc,
|
||||
sub_block, do_spill_noroot,
|
||||
dest, bcx_icx, non_gc_box_cast,
|
||||
heap, heap_exchange, heap_shared};
|
||||
INIT, copy_val, load_if_immediate, get_tydesc,
|
||||
sub_block, do_spill_noroot,
|
||||
dest, bcx_icx, non_gc_box_cast,
|
||||
heap, heap_exchange, heap_shared};
|
||||
import syntax::codemap::span;
|
||||
import shape::llsize_of;
|
||||
import build::*;
|
||||
|
|
|
|||
|
|
@ -189,14 +189,14 @@ fn mark_for_expr(cx: ctx, e: @expr) {
|
|||
type_needs(cx, use_repr, ty::type_autoderef(cx.ccx.tcx, base_ty));
|
||||
|
||||
option::iter(cx.ccx.maps.method_map.find(e.id)) {|mth|
|
||||
alt mth {
|
||||
alt mth.origin {
|
||||
typeck::method_static(did) {
|
||||
option::iter(cx.ccx.tcx.node_type_substs.find(e.id)) {|ts|
|
||||
vec::iter2(type_uses_for(cx.ccx, did, ts.len()), ts)
|
||||
{|uses, subst| type_needs(cx, uses, subst)}
|
||||
}
|
||||
}
|
||||
typeck::method_param(_, _, param, _) {
|
||||
typeck::method_param({param_num: param, _}) {
|
||||
cx.uses[param] |= use_tydesc;
|
||||
}
|
||||
typeck::method_iface(_, _) {}
|
||||
|
|
|
|||
|
|
@ -70,18 +70,54 @@ export check_crate;
|
|||
export infer;
|
||||
export method_map;
|
||||
export method_origin, serialize_method_origin, deserialize_method_origin;
|
||||
export method_map_entry, serialize_method_map_entry;
|
||||
export deserialize_method_map_entry;
|
||||
export vtable_map;
|
||||
export vtable_res;
|
||||
export vtable_origin;
|
||||
|
||||
#[auto_serialize]
|
||||
enum method_origin {
|
||||
// fully statically resolved method
|
||||
method_static(ast::def_id),
|
||||
// iface id, method num, param num, bound num
|
||||
method_param(ast::def_id, uint, uint, uint),
|
||||
|
||||
// method invoked on a type parameter with a bounded iface
|
||||
method_param(method_param),
|
||||
|
||||
// method invoked on a boxed iface
|
||||
method_iface(ast::def_id, uint),
|
||||
}
|
||||
type method_map = hashmap<ast::node_id, method_origin>;
|
||||
|
||||
// details for a method invoked with a receiver whose type is a type parameter
|
||||
// with a bounded iface.
|
||||
#[auto_serialize]
|
||||
type method_param = {
|
||||
// the iface containing the method to be invoked
|
||||
iface_id: ast::def_id,
|
||||
|
||||
// index of the method to be invoked amongst the iface's methods
|
||||
method_num: uint,
|
||||
|
||||
// index of the type parameter (from those that are in scope) that is
|
||||
// the type of the receiver
|
||||
param_num: uint,
|
||||
|
||||
// index of the bound for this type parameter which specifies the iface
|
||||
bound_num: uint
|
||||
};
|
||||
|
||||
#[auto_serialize]
|
||||
type method_map_entry = {
|
||||
// number of derefs that are required on the receiver
|
||||
derefs: uint,
|
||||
|
||||
// method details being invoked
|
||||
origin: method_origin
|
||||
};
|
||||
|
||||
// maps from an expression id that corresponds to a method call to the details
|
||||
// of the method to be invoked
|
||||
type method_map = hashmap<ast::node_id, method_map_entry>;
|
||||
|
||||
// Resolutions for bounds of all parameters, left to right, for a given path.
|
||||
type vtable_res = @[vtable_origin];
|
||||
|
|
|
|||
|
|
@ -1642,8 +1642,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||
supplied_tps: tps,
|
||||
include_private: is_self_ref});
|
||||
alt lkup.method() {
|
||||
some(origin) {
|
||||
fcx.ccx.method_map.insert(id, origin);
|
||||
some(entry) {
|
||||
fcx.ccx.method_map.insert(id, entry);
|
||||
}
|
||||
none {
|
||||
let t_err = fcx.infcx.resolve_type_vars_if_possible(expr_t);
|
||||
|
|
@ -1699,8 +1699,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
|||
supplied_tps: [],
|
||||
include_private: false});
|
||||
alt lkup.method() {
|
||||
some(origin) {
|
||||
fcx.ccx.method_map.insert(alloc_id, origin);
|
||||
some(entry) {
|
||||
fcx.ccx.method_map.insert(alloc_id, entry);
|
||||
|
||||
// Check that the alloc() method has the expected type, which
|
||||
// should be fn(sz: uint, align: uint) -> *().
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ enum lookup = {
|
|||
|
||||
impl methods for lookup {
|
||||
// Entrypoint:
|
||||
fn method() -> option<method_origin> {
|
||||
fn method() -> option<method_map_entry> {
|
||||
#debug["method lookup(m_name=%s, self_ty=%s)",
|
||||
*self.m_name, self.fcx.infcx.ty_to_str(self.self_ty)];
|
||||
|
||||
|
|
@ -45,7 +45,9 @@ impl methods for lookup {
|
|||
|
||||
fn tcx() -> ty::ctxt { self.fcx.ccx.tcx }
|
||||
|
||||
fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
|
||||
fn method_from_param(n: uint, did: ast::def_id)
|
||||
-> option<method_map_entry> {
|
||||
|
||||
let tcx = self.tcx();
|
||||
let mut iface_bnd_idx = 0u; // count only iface bounds
|
||||
let bounds = tcx.ty_param_bounds.get(did.node);
|
||||
|
|
@ -105,11 +107,15 @@ impl methods for lookup {
|
|||
|
||||
let (substs, mty, iid, pos, n, iface_bnd_idx) = candidates[0u];
|
||||
ret some(self.write_mty_from_m(
|
||||
substs, mty, method_param(iid, pos, n, iface_bnd_idx)));
|
||||
substs, mty, method_param({iface_id:iid,
|
||||
method_num:pos,
|
||||
param_num:n,
|
||||
bound_num:iface_bnd_idx})));
|
||||
}
|
||||
|
||||
fn method_from_iface(
|
||||
did: ast::def_id, iface_substs: ty::substs) -> option<method_origin> {
|
||||
did: ast::def_id, iface_substs: ty::substs)
|
||||
-> option<method_map_entry> {
|
||||
|
||||
let ms = *ty::iface_methods(self.tcx(), did);
|
||||
for ms.eachi {|i, m|
|
||||
|
|
@ -145,7 +151,7 @@ impl methods for lookup {
|
|||
}
|
||||
|
||||
fn method_from_class(did: ast::def_id, class_substs: ty::substs)
|
||||
-> option<method_origin> {
|
||||
-> option<method_map_entry> {
|
||||
|
||||
let ms = *ty::iface_methods(self.tcx(), did);
|
||||
|
||||
|
|
@ -196,7 +202,7 @@ impl methods for lookup {
|
|||
*/
|
||||
}
|
||||
|
||||
fn method_from_scope() -> option<method_origin> {
|
||||
fn method_from_scope() -> option<method_map_entry> {
|
||||
let impls_vecs = self.fcx.ccx.impl_map.get(self.expr.id);
|
||||
|
||||
for list::each(impls_vecs) {|impls|
|
||||
|
|
@ -273,7 +279,7 @@ impl methods for lookup {
|
|||
|
||||
fn write_mty_from_m(self_substs: ty::substs,
|
||||
m: ty::method,
|
||||
origin: method_origin) -> method_origin {
|
||||
origin: method_origin) -> method_map_entry {
|
||||
let tcx = self.fcx.ccx.tcx;
|
||||
|
||||
// a bit hokey, but the method unbound has a bare protocol, whereas
|
||||
|
|
@ -287,7 +293,7 @@ impl methods for lookup {
|
|||
fn write_mty_from_fty(self_substs: ty::substs,
|
||||
n_tps_m: uint,
|
||||
fty: ty::t,
|
||||
origin: method_origin) -> method_origin {
|
||||
origin: method_origin) -> method_map_entry {
|
||||
|
||||
let tcx = self.fcx.ccx.tcx;
|
||||
|
||||
|
|
@ -324,7 +330,7 @@ impl methods for lookup {
|
|||
|
||||
self.fcx.write_ty_substs(self.node_id, fty, all_substs);
|
||||
|
||||
ret origin;
|
||||
ret {derefs:0u, origin:origin};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ fn resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, v: visit::vt<@fn_ctxt>) {
|
|||
ast::expr_unary(*) | ast::expr_assign_op(*) |
|
||||
ast::expr_index(*) {
|
||||
alt cx.method_map.find(ex.id) {
|
||||
some(method_static(did)) {
|
||||
some({origin: method_static(did), _}) {
|
||||
let bounds = ty::lookup_item_type(cx.tcx, did).bounds;
|
||||
if has_iface_bounds(*bounds) {
|
||||
let callee_id = alt ex.node {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
// xfail-fast (compile-flags unsupported on windows)
|
||||
// compile-flags:--borrowck=err
|
||||
|
||||
fn main() {
|
||||
let x = [22]/1;
|
||||
let y = &x[0];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue