]> git.lizzy.rs Git - rust.git/commitdiff
first steps to autoderef on method calls
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 7 Jun 2012 17:51:21 +0000 (10:51 -0700)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 19 Jun 2012 18:52:39 +0000 (11:52 -0700)
12 files changed:
src/rustc/middle/astencode.rs
src/rustc/middle/kind.rs
src/rustc/middle/trans/base.rs
src/rustc/middle/trans/impl.rs
src/rustc/middle/trans/reachable.rs
src/rustc/middle/trans/tvec.rs
src/rustc/middle/trans/type_use.rs
src/rustc/middle/typeck.rs
src/rustc/middle/typeck/check.rs
src/rustc/middle/typeck/check/method.rs
src/rustc/middle/typeck/check/vtable.rs
src/test/run-pass/borrowck-fixed-length-vecs.rs

index 035f106d1f3a9f477d7e1b3b800ebba47b8001fa..99542973c179eed918f20d1fa9245c5cc7f69395 100644 (file)
@@ -20,9 +20,9 @@
 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 @@ fn tr(xcx: extended_decode_ctxt) -> 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 @@ fn tr(xcx: extended_decode_ctxt) -> 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));
index 8e77777828e2e4b5e8acbfd30d70ba9b3d4ef450..4bec0e35e7e244fddfc2b8cfa32f2e0c0a2f9ff9 100644 (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
index d6520b45d4a03f41bdad9d5be1c2a9af4f727d95..c532e51c584b61b6f5bd079456dde4b92ae18de2 100644 (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);
-        }
+          }
+
+          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);
+            }
+          }
 
-        // 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_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
index 044a05b3b0bd45364507b7cc6f2afc817eae4bc6..514a73726602a4d9b703846af93b7c05677005ba 100644 (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),
index 55a4b865e903ba2f68a03b1d9b5405b3141c1839..4ca10198f177e979e65f3ab235a756b09f0524d8 100644 (file)
@@ -180,7 +180,9 @@ fn traverse_expr(e: @expr, cx: ctx, v: visit::vt<ctx>) {
           }
           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);
+              }
               _ {}
             }
           }
index 72e82a96709038e110c5cd98fa7d23ca9271536f..1eca2db5e7d5f0def2b0790f7b60525924aa56e1 100644 (file)
@@ -3,10 +3,10 @@
 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::*;
index e42028fbdf6c20c3a8d1651b93bb911af0995ed6..6b453b9d9dc52791d0ba4b647e91394afb7370c3 100644 (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(_, _) {}
index c05e95650ab2c624dc8e98818a799f49f739141c..ec7ec06080c6ac48d7b961155ec79b88846cbb74 100644 (file)
 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];
index 0ca184e5916577ae1064ae0114771d75f8407037..9b9b92e1e01153bfdd2530fa0b14bea8cf748d18 100644 (file)
@@ -1642,8 +1642,8 @@ fn get_node(f: spanned<field>) -> field { f.node }
                                        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 get_node(f: spanned<field>) -> field { f.node }
                                    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) -> *().
index 22d51093fa301caa53c3f4d5382d1c3815e68ca0..143a477302bde7b7caf6b95b7d4db1bba27d9fa6 100644 (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 @@ fn method() -> option<method_origin> {
 
     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 @@ fn method_from_param(n: uint, did: ast::def_id) -> option<method_origin> {
 
         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 @@ fn method_from_iface(
     }
 
     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 @@ fn ty_from_did(did: ast::def_id) -> ty::t {
         */
     }
 
-    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 @@ fn method_from_scope() -> option<method_origin> {
 
     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 @@ fn write_mty_from_m(self_substs: ty::substs,
     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 @@ fn write_mty_from_fty(self_substs: ty::substs,
 
         self.fcx.write_ty_substs(self.node_id, fty, all_substs);
 
-        ret origin;
+        ret {derefs:0u, origin:origin};
     }
 }
 
index 1182adfb811672f4139e32336083035ac53a65a4..d772f6861dedd0fc9e9eae771c9a0a2d14dd153b 100644 (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 {
index 538d1f4c5210348ed5917205aa869a68da2ee0de..9d79e28b219d00e60cd490c04eecd0de85d02b11 100644 (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];