about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLuqman Aden <laden@csclub.uwaterloo.ca>2014-06-11 18:01:48 -0400
committerLuqman Aden <laden@csclub.uwaterloo.ca>2014-06-17 23:47:17 -0400
commit4eb5d7baf928a922b30d71e64f7be258d1a82f2f (patch)
tree2bbad07192bbc98d2ef70456b3ddcdda1050b8f3
parent5c81a186e9d835ca66865bd9807524b805a06d8d (diff)
downloadrust-4eb5d7baf928a922b30d71e64f7be258d1a82f2f.tar.gz
rust-4eb5d7baf928a922b30d71e64f7be258d1a82f2f.zip
librustc: Don't overwrite vtables when coercing to trait object.
-rw-r--r--src/librustc/middle/astencode.rs70
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs7
-rw-r--r--src/librustc/middle/trans/expr.rs34
-rw-r--r--src/librustc/middle/trans/meth.rs10
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/librustc/middle/typeck/check/mod.rs3
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs2
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs12
-rw-r--r--src/librustc/middle/typeck/check/writeback.rs6
-rw-r--r--src/librustc/middle/typeck/mod.rs36
-rw-r--r--src/test/run-pass/deref-rc.rs16
-rw-r--r--src/test/run-pass/issue-14399.rs25
13 files changed, 164 insertions, 61 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index c7524c11188..8cb975182a0 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -552,16 +552,17 @@ impl tr for freevar_entry {
 // Encoding and decoding of MethodCallee
 
 trait read_method_callee_helper {
-    fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) -> (u32, MethodCallee);
+    fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext)
+        -> (typeck::ExprAdjustment, MethodCallee);
 }
 
 fn encode_method_callee(ecx: &e::EncodeContext,
                         ebml_w: &mut Encoder,
-                        autoderef: u32,
+                        adjustment: typeck::ExprAdjustment,
                         method: &MethodCallee) {
     ebml_w.emit_struct("MethodCallee", 4, |ebml_w| {
-        ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| {
-            autoderef.encode(ebml_w)
+        ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| {
+            adjustment.encode(ebml_w)
         });
         ebml_w.emit_struct_field("origin", 1u, |ebml_w| {
             method.origin.encode(ebml_w)
@@ -576,12 +577,14 @@ fn encode_method_callee(ecx: &e::EncodeContext,
 }
 
 impl<'a> read_method_callee_helper for reader::Decoder<'a> {
-    fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext) -> (u32, MethodCallee) {
+    fn read_method_callee(&mut self, xcx: &ExtendedDecodeContext)
+        -> (typeck::ExprAdjustment, MethodCallee) {
+
         self.read_struct("MethodCallee", 4, |this| {
-            let autoderef = this.read_struct_field("autoderef", 0, |this| {
+            let adjustment = this.read_struct_field("adjustment", 0, |this| {
                 Decodable::decode(this)
             }).unwrap();
-            Ok((autoderef, MethodCallee {
+            Ok((adjustment, MethodCallee {
                 origin: this.read_struct_field("origin", 1, |this| {
                     let method_origin: MethodOrigin =
                         Decodable::decode(this).unwrap();
@@ -627,11 +630,11 @@ impl tr for MethodOrigin {
 
 fn encode_vtable_res_with_key(ecx: &e::EncodeContext,
                               ebml_w: &mut Encoder,
-                              autoderef: u32,
+                              adjustment: typeck::ExprAdjustment,
                               dr: &typeck::vtable_res) {
     ebml_w.emit_struct("VtableWithKey", 2, |ebml_w| {
-        ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| {
-            autoderef.encode(ebml_w)
+        ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| {
+            adjustment.encode(ebml_w)
         });
         ebml_w.emit_struct_field("vtable_res", 1u, |ebml_w| {
             Ok(encode_vtable_res(ecx, ebml_w, dr))
@@ -705,7 +708,7 @@ pub trait vtable_decoder_helpers {
     fn read_vtable_res_with_key(&mut self,
                                 tcx: &ty::ctxt,
                                 cdata: &cstore::crate_metadata)
-                                -> (u32, typeck::vtable_res);
+                                -> (typeck::ExprAdjustment, typeck::vtable_res);
     fn read_vtable_res(&mut self,
                        tcx: &ty::ctxt, cdata: &cstore::crate_metadata)
                       -> typeck::vtable_res;
@@ -731,12 +734,12 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
     fn read_vtable_res_with_key(&mut self,
                                 tcx: &ty::ctxt,
                                 cdata: &cstore::crate_metadata)
-                                -> (u32, typeck::vtable_res) {
+                                -> (typeck::ExprAdjustment, typeck::vtable_res) {
         self.read_struct("VtableWithKey", 2, |this| {
-            let autoderef = this.read_struct_field("autoderef", 0, |this| {
+            let adjustment = this.read_struct_field("adjustment", 0, |this| {
                 Decodable::decode(this)
             }).unwrap();
-            Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| {
+            Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| {
                 Ok(this.read_vtable_res(tcx, cdata))
             }).unwrap()))
         }).unwrap()
@@ -1050,7 +1053,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         ebml_w.tag(c::tag_table_method_map, |ebml_w| {
             ebml_w.id(id);
             ebml_w.tag(c::tag_table_val, |ebml_w| {
-                encode_method_callee(ecx, ebml_w, method_call.autoderef, method)
+                encode_method_callee(ecx, ebml_w, method_call.adjustment, method)
             })
         })
     }
@@ -1059,7 +1062,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         ebml_w.tag(c::tag_table_vtable_map, |ebml_w| {
             ebml_w.id(id);
             ebml_w.tag(c::tag_table_val, |ebml_w| {
-                encode_vtable_res_with_key(ecx, ebml_w, method_call.autoderef, dr);
+                encode_vtable_res_with_key(ecx, ebml_w, method_call.adjustment, dr);
             })
         })
     }
@@ -1068,12 +1071,13 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
         match *adj {
             ty::AutoDerefRef(adj) => {
                 for autoderef in range(0, adj.autoderefs) {
-                    let method_call = MethodCall::autoderef(id, autoderef as u32);
+                    let method_call = MethodCall::autoderef(id, autoderef);
                     for &method in tcx.method_map.borrow().find(&method_call).iter() {
                         ebml_w.tag(c::tag_table_method_map, |ebml_w| {
                             ebml_w.id(id);
                             ebml_w.tag(c::tag_table_val, |ebml_w| {
-                                encode_method_callee(ecx, ebml_w, method_call.autoderef, method)
+                                encode_method_callee(ecx, ebml_w,
+                                                     method_call.adjustment, method)
                             })
                         })
                     }
@@ -1083,12 +1087,32 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
                             ebml_w.id(id);
                             ebml_w.tag(c::tag_table_val, |ebml_w| {
                                 encode_vtable_res_with_key(ecx, ebml_w,
-                                                           method_call.autoderef, dr);
+                                                           method_call.adjustment, dr);
                             })
                         })
                     }
                 }
             }
+            ty::AutoObject(..) => {
+                let method_call = MethodCall::autoobject(id);
+                for &method in tcx.method_map.borrow().find(&method_call).iter() {
+                    ebml_w.tag(c::tag_table_method_map, |ebml_w| {
+                        ebml_w.id(id);
+                        ebml_w.tag(c::tag_table_val, |ebml_w| {
+                            encode_method_callee(ecx, ebml_w, method_call.adjustment, method)
+                        })
+                    })
+                }
+
+                for &dr in tcx.vtable_map.borrow().find(&method_call).iter() {
+                    ebml_w.tag(c::tag_table_vtable_map, |ebml_w| {
+                        ebml_w.id(id);
+                        ebml_w.tag(c::tag_table_val, |ebml_w| {
+                            encode_vtable_res_with_key(ecx, ebml_w, method_call.adjustment, dr);
+                        })
+                    })
+                }
+            }
             _ => {}
         }
 
@@ -1393,20 +1417,20 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
                         dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds);
                     }
                     c::tag_table_method_map => {
-                        let (autoderef, method) = val_dsr.read_method_callee(xcx);
+                        let (adjustment, method) = val_dsr.read_method_callee(xcx);
                         let method_call = MethodCall {
                             expr_id: id,
-                            autoderef: autoderef
+                            adjustment: adjustment
                         };
                         dcx.tcx.method_map.borrow_mut().insert(method_call, method);
                     }
                     c::tag_table_vtable_map => {
-                        let (autoderef, vtable_res) =
+                        let (adjustment, vtable_res) =
                             val_dsr.read_vtable_res_with_key(xcx.dcx.tcx,
                                                              xcx.dcx.cdata);
                         let vtable_key = MethodCall {
                             expr_id: id,
-                            autoderef: autoderef
+                            adjustment: adjustment
                         };
                         dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res);
                     }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 86cd3c53804..f70123313c4 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -611,7 +611,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
         debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
 
         for i in range(0, autoderefs) {
-            let deref_id = typeck::MethodCall::autoderef(expr.id, i as u32);
+            let deref_id = typeck::MethodCall::autoderef(expr.id, i);
             match self.typer.node_method_ty(deref_id) {
                 None => {}
                 Some(method_ty) => {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 8224557f860..ea083e41099 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -697,9 +697,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
                              base_cmt: cmt,
                              deref_cnt: uint)
                              -> cmt {
+        let adjustment = match self.typer.adjustments().borrow().find(&node.id()) {
+            Some(&ty::AutoObject(..)) => typeck::AutoObject,
+            _ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt),
+            _ => typeck::NoAdjustment
+        };
         let method_call = typeck::MethodCall {
             expr_id: node.id(),
-            autoderef: deref_cnt as u32
+            adjustment: adjustment
         };
         let method_ty = self.typer.node_method_ty(method_call);
 
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index 42c7a71bab8..8b9ed86b677 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -65,8 +65,8 @@ use middle::ty::struct_fields;
 use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
 use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
 use middle::ty;
-use middle::typeck::MethodCall;
 use middle::typeck;
+use middle::typeck::MethodCall;
 use util::common::indenter;
 use util::ppaux::Repr;
 use util::nodemap::NodeMap;
@@ -1178,7 +1178,7 @@ fn trans_unary<'a>(bcx: &'a Block<'a>,
         }
         ast::UnDeref => {
             let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
-            deref_once(bcx, expr, datum, 0)
+            deref_once(bcx, expr, datum, method_call)
         }
     }
 }
@@ -1487,7 +1487,7 @@ fn trans_overloaded_call<'a>(
                       SaveIn(addr))
         }));
 
-    let method_call = typeck::MethodCall::expr(expr.id);
+    let method_call = MethodCall::expr(expr.id);
     let method_type = bcx.tcx()
                          .method_map
                          .borrow()
@@ -1737,8 +1737,9 @@ fn deref_multiple<'a>(bcx: &'a Block<'a>,
                       -> DatumBlock<'a, Expr> {
     let mut bcx = bcx;
     let mut datum = datum;
-    for i in range(1, times+1) {
-        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i));
+    for i in range(0, times) {
+        let method_call = MethodCall::autoderef(expr.id, i);
+        datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
     }
     DatumBlock { bcx: bcx, datum: datum }
 }
@@ -1746,22 +1747,18 @@ fn deref_multiple<'a>(bcx: &'a Block<'a>,
 fn deref_once<'a>(bcx: &'a Block<'a>,
                   expr: &ast::Expr,
                   datum: Datum<Expr>,
-                  derefs: uint)
+                  method_call: MethodCall)
                   -> DatumBlock<'a, Expr> {
     let ccx = bcx.ccx();
 
-    debug!("deref_once(expr={}, datum={}, derefs={})",
+    debug!("deref_once(expr={}, datum={}, method_call={})",
            expr.repr(bcx.tcx()),
            datum.to_str(ccx),
-           derefs);
+           method_call);
 
     let mut bcx = bcx;
 
     // Check for overloaded deref.
-    let method_call = MethodCall {
-        expr_id: expr.id,
-        autoderef: derefs as u32
-    };
     let method_ty = ccx.tcx.method_map.borrow()
                        .find(&method_call).map(|method| method.ty);
     let datum = match method_ty {
@@ -1771,11 +1768,10 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
             // converts from the `Shaht<T>` pointer that we have into
             // a `&T` pointer.  We can then proceed down the normal
             // path (below) to dereference that `&T`.
-            let datum = if derefs == 0 {
-                datum
-            } else {
-                // Always perform an AutoPtr when applying an overloaded auto-deref.
-                unpack_datum!(bcx, auto_ref(bcx, datum, expr))
+            let datum = match method_call.adjustment {
+                // Always perform an AutoPtr when applying an overloaded auto-deref
+                typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
+                _ => datum
             };
             let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
                                                               datum, None, None));
@@ -1834,8 +1830,8 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
         }
     };
 
-    debug!("deref_once(expr={}, derefs={}, result={})",
-           expr.id, derefs, r.datum.to_str(ccx));
+    debug!("deref_once(expr={}, method_call={}, result={})",
+           expr.id, method_call, r.datum.to_str(ccx));
 
     return r;
 
diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs
index bde48b94473..85660cd2eb5 100644
--- a/src/librustc/middle/trans/meth.rs
+++ b/src/librustc/middle/trans/meth.rs
@@ -538,9 +538,13 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
     // Store the vtable into the second half of pair.
     let origins = {
         let vtable_map = ccx.tcx.vtable_map.borrow();
-        resolve_param_vtables_under_param_substs(ccx.tcx(),
-            bcx.fcx.param_substs,
-            vtable_map.get(&MethodCall::expr(id)).get_self().unwrap())
+        // This trait cast might be because of implicit coercion
+        let method_call = match ccx.tcx.adjustments.borrow().find(&id) {
+            Some(&ty::AutoObject(..)) => MethodCall::autoobject(id),
+            _ => MethodCall::expr(id)
+        };
+        let vres = vtable_map.get(&method_call).get_self().unwrap();
+        resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres)
     };
     let vtable = get_vtable(bcx, v_ty, origins);
     let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]);
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index ac1b6ca591b..c4e48bea85e 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2823,7 +2823,7 @@ pub fn adjust_ty(cx: &ctxt,
 
                     if !ty::type_is_error(adjusted_ty) {
                         for i in range(0, adj.autoderefs) {
-                            let method_call = typeck::MethodCall::autoderef(expr_id, i as u32);
+                            let method_call = typeck::MethodCall::autoderef(expr_id, i);
                             match method_type(method_call) {
                                 Some(method_ty) => {
                                     adjusted_ty = ty_fn_ret(method_ty);
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 7d647dea322..6016bc54e01 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1331,8 +1331,7 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
         let mt = match ty::deref(resolved_t, false) {
             Some(mt) => Some(mt),
             None => {
-                let method_call =
-                    expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
+                let method_call = expr_id.map(|id| MethodCall::autoderef(id, autoderefs));
                 try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
             }
         };
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index 1069f0a67a2..4cd319af0d9 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -879,7 +879,7 @@ fn constrain_autoderefs(rcx: &mut Rcx,
                rcx.fcx.infcx().ty_to_str(derefd_ty),
                i, derefs);
 
-        let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
+        let method_call = MethodCall::autoderef(deref_expr.id, i);
         derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
             Some(method) => {
                 // Treat overloaded autoderefs as if an AutoRef adjustment
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index fe79dabc3f8..6ac6cdce859 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -529,7 +529,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
     let _indent = indenter();
 
     let cx = fcx.ccx;
-    let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t| {
+    let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t, key: MethodCall| {
       // Look up vtables for the type we're casting to,
       // passing in the source and target type.  The source
       // must be a pointer type suitable to the object sigil,
@@ -596,7 +596,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
                       if !is_early {
                           let mut r = VecPerParamSpace::empty();
                           r.push(subst::SelfSpace, vtables);
-                          insert_vtables(fcx, MethodCall::expr(ex.id), r);
+                          insert_vtables(fcx, key, r);
                       }
 
                       // Now, if this is &trait, we need to link the
@@ -694,7 +694,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
       ast::ExprCast(ref src, _) => {
           debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
           let target_ty = fcx.expr_ty(ex);
-          resolve_object_cast(&**src, target_ty);
+          let key = MethodCall::expr(ex.id);
+          resolve_object_cast(&**src, target_ty, key);
       }
       _ => ()
     }
@@ -705,7 +706,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
             match *adjustment {
                 AutoDerefRef(adj) => {
                     for autoderef in range(0, adj.autoderefs) {
-                        let method_call = MethodCall::autoderef(ex.id, autoderef as u32);
+                        let method_call = MethodCall::autoderef(ex.id, autoderef);
                         match fcx.inh.method_map.borrow().find(&method_call) {
                             Some(method) => {
                                 debug!("vtable resolution on parameter bounds for autoderef {}",
@@ -745,7 +746,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
                         }
                     };
 
-                    resolve_object_cast(ex, object_ty);
+                    let key = MethodCall::autoobject(ex.id);
+                    resolve_object_cast(ex, object_ty, key);
                 }
                 AutoAddEnv(..) => {}
             }
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index db9e90ecd50..8e3e8e6091b 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -248,7 +248,7 @@ impl<'cx> WritebackCx<'cx> {
 
                     ty::AutoDerefRef(adj) => {
                         for autoderef in range(0, adj.autoderefs) {
-                            let method_call = MethodCall::autoderef(id, autoderef as u32);
+                            let method_call = MethodCall::autoderef(id, autoderef);
                             self.visit_method_map_entry(reason, method_call);
                             self.visit_vtable_map_entry(reason, method_call);
                         }
@@ -260,6 +260,10 @@ impl<'cx> WritebackCx<'cx> {
                     }
 
                     ty::AutoObject(trait_store, bb, def_id, substs) => {
+                        let method_call = MethodCall::autoobject(id);
+                        self.visit_method_map_entry(reason, method_call);
+                        self.visit_vtable_map_entry(reason, method_call);
+
                         ty::AutoObject(
                             self.resolve(&trait_store, reason),
                             self.resolve(&bb, reason),
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index b5c103b8481..bc2768ce214 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -149,24 +149,52 @@ pub struct MethodCallee {
     pub substs: subst::Substs
 }
 
+/**
+ * With method calls, we store some extra information in
+ * side tables (i.e method_map, vtable_map). We use
+ * MethodCall as a key to index into these tables instead of
+ * just directly using the expression's NodeId. The reason
+ * for this being that we may apply adjustments (coercions)
+ * with the resulting expression also needing to use the
+ * side tables. The problem with this is that we don't
+ * assign a separate NodeId to this new expression
+ * and so it would clash with the base expression if both
+ * needed to add to the side tables. Thus to disambiguate
+ * we also keep track of whether there's an adjustment in
+ * our key.
+ */
 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
 pub struct MethodCall {
     pub expr_id: ast::NodeId,
-    pub autoderef: u32
+    pub adjustment: ExprAdjustment
+}
+
+#[deriving(Clone, PartialEq, Eq, Hash, Show, Encodable, Decodable)]
+pub enum ExprAdjustment {
+    NoAdjustment,
+    AutoDeref(uint),
+    AutoObject
 }
 
 impl MethodCall {
     pub fn expr(id: ast::NodeId) -> MethodCall {
         MethodCall {
             expr_id: id,
-            autoderef: 0
+            adjustment: NoAdjustment
+        }
+    }
+
+    pub fn autoobject(id: ast::NodeId) -> MethodCall {
+        MethodCall {
+            expr_id: id,
+            adjustment: AutoObject
         }
     }
 
-    pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall {
+    pub fn autoderef(expr_id: ast::NodeId, autoderef: uint) -> MethodCall {
         MethodCall {
             expr_id: expr_id,
-            autoderef: 1 + autoderef
+            adjustment: AutoDeref(1 + autoderef)
         }
     }
 }
diff --git a/src/test/run-pass/deref-rc.rs b/src/test/run-pass/deref-rc.rs
new file mode 100644
index 00000000000..fbb8a3a1720
--- /dev/null
+++ b/src/test/run-pass/deref-rc.rs
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+
+fn main() {
+    let x = Rc::new([1, 2, 3, 4]);
+    assert!(*x == [1, 2, 3, 4]);
+}
diff --git a/src/test/run-pass/issue-14399.rs b/src/test/run-pass/issue-14399.rs
new file mode 100644
index 00000000000..4c84d0fcaf0
--- /dev/null
+++ b/src/test/run-pass/issue-14399.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// #14399
+// We'd previously ICE if we had a method call whose return
+// value was coerced to a trait object. (v.clone() returns Box<B1>
+// which is coerced to Box<A>).
+
+#[deriving(Clone)]
+struct B1;
+
+trait A {}
+impl A for B1 {}
+
+fn main() {
+    let v = box B1;
+    let _c: Box<A> = v.clone();
+}