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, - 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` 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(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 autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall { + pub fn autoobject(id: ast::NodeId) -> MethodCall { + MethodCall { + expr_id: id, + adjustment: AutoObject + } + } + + 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 or the MIT license +// , 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 or the MIT license +// , 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 +// which is coerced to Box). + +#[deriving(Clone)] +struct B1; + +trait A {} +impl A for B1 {} + +fn main() { + let v = box B1; + let _c: Box = v.clone(); +}