first steps to autoderef on method calls

This commit is contained in:
Niko Matsakis 2012-06-07 10:51:21 -07:00
parent 6c056fba4d
commit 6e73e45e37
12 changed files with 198 additions and 118 deletions

View file

@ -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));

View file

@ -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

View file

@ -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

View file

@ -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),

View file

@ -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);
}
_ {}
}
}

View file

@ -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::*;

View file

@ -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(_, _) {}

View file

@ -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];

View file

@ -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) -> *().

View file

@ -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};
}
}

View file

@ -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 {

View file

@ -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];