From 6e73e45e372a0dfc5a2ebf19780dc392ec092492 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 7 Jun 2012 10:51:21 -0700 Subject: [PATCH] first steps to autoderef on method calls --- src/rustc/middle/astencode.rs | 31 ++-- src/rustc/middle/kind.rs | 5 +- src/rustc/middle/trans/base.rs | 163 +++++++++++------- src/rustc/middle/trans/impl.rs | 22 +-- src/rustc/middle/trans/reachable.rs | 4 +- src/rustc/middle/trans/tvec.rs | 8 +- src/rustc/middle/trans/type_use.rs | 4 +- src/rustc/middle/typeck.rs | 42 ++++- src/rustc/middle/typeck/check.rs | 8 +- src/rustc/middle/typeck/check/method.rs | 24 ++- src/rustc/middle/typeck/check/vtable.rs | 2 +- .../run-pass/borrowck-fixed-length-vecs.rs | 3 - 12 files changed, 198 insertions(+), 118 deletions(-) diff --git a/src/rustc/middle/astencode.rs b/src/rustc/middle/astencode.rs index 035f106d1f3a..99542973c179 100644 --- a/src/rustc/middle/astencode.rs +++ b/src/rustc/middle/astencode.rs @@ -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)); diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 8e77777828e2..4bec0e35e7e2 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -261,14 +261,15 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt) { 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 diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index d6520b45d4a0..c532e51c584b 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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, // 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) + &temp_cleanups: [ValueRef], ret_flag: option, + 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 diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 044a05b3b0bd..514a73726602 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -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), diff --git a/src/rustc/middle/trans/reachable.rs b/src/rustc/middle/trans/reachable.rs index 55a4b865e903..4ca10198f177 100644 --- a/src/rustc/middle/trans/reachable.rs +++ b/src/rustc/middle/trans/reachable.rs @@ -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); + } _ {} } } diff --git a/src/rustc/middle/trans/tvec.rs b/src/rustc/middle/trans/tvec.rs index 72e82a967090..1eca2db5e7d5 100644 --- a/src/rustc/middle/trans/tvec.rs +++ b/src/rustc/middle/trans/tvec.rs @@ -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::*; diff --git a/src/rustc/middle/trans/type_use.rs b/src/rustc/middle/trans/type_use.rs index e42028fbdf6c..6b453b9d9dc5 100644 --- a/src/rustc/middle/trans/type_use.rs +++ b/src/rustc/middle/trans/type_use.rs @@ -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(_, _) {} diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index c05e95650ab2..ec7ec06080c6 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -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; + +// 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; // Resolutions for bounds of all parameters, left to right, for a given path. type vtable_res = @[vtable_origin]; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 0ca184e59165..9b9b92e1e011 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -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) -> *(). diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index 22d51093fa30..143a477302bd 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -17,7 +17,7 @@ enum lookup = { impl methods for lookup { // Entrypoint: - fn method() -> option { + fn method() -> option { #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 { + fn method_from_param(n: uint, did: ast::def_id) + -> option { + 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 { + did: ast::def_id, iface_substs: ty::substs) + -> option { 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 { + -> option { let ms = *ty::iface_methods(self.tcx(), did); @@ -196,7 +202,7 @@ impl methods for lookup { */ } - fn method_from_scope() -> option { + fn method_from_scope() -> option { 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}; } } diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index 1182adfb8116..d772f6861ded 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -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 { diff --git a/src/test/run-pass/borrowck-fixed-length-vecs.rs b/src/test/run-pass/borrowck-fixed-length-vecs.rs index 538d1f4c5210..9d79e28b219d 100644 --- a/src/test/run-pass/borrowck-fixed-length-vecs.rs +++ b/src/test/run-pass/borrowck-fixed-length-vecs.rs @@ -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];