librustc: Don't overwrite vtables when coercing to trait object.

This commit is contained in:
Luqman Aden 2014-06-11 18:01:48 -04:00
parent 5c81a186e9
commit 4eb5d7baf9
13 changed files with 164 additions and 61 deletions

View File

@ -552,16 +552,17 @@ impl tr for freevar_entry {
// Encoding and decoding of MethodCallee // Encoding and decoding of MethodCallee
trait read_method_callee_helper { 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, fn encode_method_callee(ecx: &e::EncodeContext,
ebml_w: &mut Encoder, ebml_w: &mut Encoder,
autoderef: u32, adjustment: typeck::ExprAdjustment,
method: &MethodCallee) { method: &MethodCallee) {
ebml_w.emit_struct("MethodCallee", 4, |ebml_w| { ebml_w.emit_struct("MethodCallee", 4, |ebml_w| {
ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| { ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| {
autoderef.encode(ebml_w) adjustment.encode(ebml_w)
}); });
ebml_w.emit_struct_field("origin", 1u, |ebml_w| { ebml_w.emit_struct_field("origin", 1u, |ebml_w| {
method.origin.encode(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> { 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| { 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) Decodable::decode(this)
}).unwrap(); }).unwrap();
Ok((autoderef, MethodCallee { Ok((adjustment, MethodCallee {
origin: this.read_struct_field("origin", 1, |this| { origin: this.read_struct_field("origin", 1, |this| {
let method_origin: MethodOrigin = let method_origin: MethodOrigin =
Decodable::decode(this).unwrap(); Decodable::decode(this).unwrap();
@ -627,11 +630,11 @@ impl tr for MethodOrigin {
fn encode_vtable_res_with_key(ecx: &e::EncodeContext, fn encode_vtable_res_with_key(ecx: &e::EncodeContext,
ebml_w: &mut Encoder, ebml_w: &mut Encoder,
autoderef: u32, adjustment: typeck::ExprAdjustment,
dr: &typeck::vtable_res) { dr: &typeck::vtable_res) {
ebml_w.emit_struct("VtableWithKey", 2, |ebml_w| { ebml_w.emit_struct("VtableWithKey", 2, |ebml_w| {
ebml_w.emit_struct_field("autoderef", 0u, |ebml_w| { ebml_w.emit_struct_field("adjustment", 0u, |ebml_w| {
autoderef.encode(ebml_w) adjustment.encode(ebml_w)
}); });
ebml_w.emit_struct_field("vtable_res", 1u, |ebml_w| { ebml_w.emit_struct_field("vtable_res", 1u, |ebml_w| {
Ok(encode_vtable_res(ecx, ebml_w, dr)) 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, fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt, tcx: &ty::ctxt,
cdata: &cstore::crate_metadata) cdata: &cstore::crate_metadata)
-> (u32, typeck::vtable_res); -> (typeck::ExprAdjustment, typeck::vtable_res);
fn read_vtable_res(&mut self, fn read_vtable_res(&mut self,
tcx: &ty::ctxt, cdata: &cstore::crate_metadata) tcx: &ty::ctxt, cdata: &cstore::crate_metadata)
-> typeck::vtable_res; -> typeck::vtable_res;
@ -731,12 +734,12 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> {
fn read_vtable_res_with_key(&mut self, fn read_vtable_res_with_key(&mut self,
tcx: &ty::ctxt, tcx: &ty::ctxt,
cdata: &cstore::crate_metadata) cdata: &cstore::crate_metadata)
-> (u32, typeck::vtable_res) { -> (typeck::ExprAdjustment, typeck::vtable_res) {
self.read_struct("VtableWithKey", 2, |this| { 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) Decodable::decode(this)
}).unwrap(); }).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)) Ok(this.read_vtable_res(tcx, cdata))
}).unwrap())) }).unwrap()))
}).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.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id); ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| { 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.tag(c::tag_table_vtable_map, |ebml_w| {
ebml_w.id(id); ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| { 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 { match *adj {
ty::AutoDerefRef(adj) => { ty::AutoDerefRef(adj) => {
for autoderef in range(0, adj.autoderefs) { 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() { for &method in tcx.method_map.borrow().find(&method_call).iter() {
ebml_w.tag(c::tag_table_method_map, |ebml_w| { ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id); ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| { 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.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| { ebml_w.tag(c::tag_table_val, |ebml_w| {
encode_vtable_res_with_key(ecx, 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); dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds);
} }
c::tag_table_method_map => { 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 { let method_call = MethodCall {
expr_id: id, expr_id: id,
autoderef: autoderef adjustment: adjustment
}; };
dcx.tcx.method_map.borrow_mut().insert(method_call, method); dcx.tcx.method_map.borrow_mut().insert(method_call, method);
} }
c::tag_table_vtable_map => { c::tag_table_vtable_map => {
let (autoderef, vtable_res) = let (adjustment, vtable_res) =
val_dsr.read_vtable_res_with_key(xcx.dcx.tcx, val_dsr.read_vtable_res_with_key(xcx.dcx.tcx,
xcx.dcx.cdata); xcx.dcx.cdata);
let vtable_key = MethodCall { let vtable_key = MethodCall {
expr_id: id, expr_id: id,
autoderef: autoderef adjustment: adjustment
}; };
dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res); dcx.tcx.vtable_map.borrow_mut().insert(vtable_key, vtable_res);
} }

View File

@ -611,7 +611,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
for i in range(0, 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) { match self.typer.node_method_ty(deref_id) {
None => {} None => {}
Some(method_ty) => { Some(method_ty) => {

View File

@ -697,9 +697,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
base_cmt: cmt, base_cmt: cmt,
deref_cnt: uint) deref_cnt: uint)
-> cmt { -> 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 { let method_call = typeck::MethodCall {
expr_id: node.id(), expr_id: node.id(),
autoderef: deref_cnt as u32 adjustment: adjustment
}; };
let method_ty = self.typer.node_method_ty(method_call); let method_ty = self.typer.node_method_ty(method_call);

View File

@ -65,8 +65,8 @@ use middle::ty::struct_fields;
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe}; use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef}; use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
use middle::ty; use middle::ty;
use middle::typeck::MethodCall;
use middle::typeck; use middle::typeck;
use middle::typeck::MethodCall;
use util::common::indenter; use util::common::indenter;
use util::ppaux::Repr; use util::ppaux::Repr;
use util::nodemap::NodeMap; use util::nodemap::NodeMap;
@ -1178,7 +1178,7 @@ fn trans_unary<'a>(bcx: &'a Block<'a>,
} }
ast::UnDeref => { ast::UnDeref => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); 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)) SaveIn(addr))
})); }));
let method_call = typeck::MethodCall::expr(expr.id); let method_call = MethodCall::expr(expr.id);
let method_type = bcx.tcx() let method_type = bcx.tcx()
.method_map .method_map
.borrow() .borrow()
@ -1737,8 +1737,9 @@ fn deref_multiple<'a>(bcx: &'a Block<'a>,
-> DatumBlock<'a, Expr> { -> DatumBlock<'a, Expr> {
let mut bcx = bcx; let mut bcx = bcx;
let mut datum = datum; let mut datum = datum;
for i in range(1, times+1) { for i in range(0, times) {
datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, i)); let method_call = MethodCall::autoderef(expr.id, i);
datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call));
} }
DatumBlock { bcx: bcx, datum: datum } 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>, fn deref_once<'a>(bcx: &'a Block<'a>,
expr: &ast::Expr, expr: &ast::Expr,
datum: Datum<Expr>, datum: Datum<Expr>,
derefs: uint) method_call: MethodCall)
-> DatumBlock<'a, Expr> { -> DatumBlock<'a, Expr> {
let ccx = bcx.ccx(); let ccx = bcx.ccx();
debug!("deref_once(expr={}, datum={}, derefs={})", debug!("deref_once(expr={}, datum={}, method_call={})",
expr.repr(bcx.tcx()), expr.repr(bcx.tcx()),
datum.to_str(ccx), datum.to_str(ccx),
derefs); method_call);
let mut bcx = bcx; let mut bcx = bcx;
// Check for overloaded deref. // Check for overloaded deref.
let method_call = MethodCall {
expr_id: expr.id,
autoderef: derefs as u32
};
let method_ty = ccx.tcx.method_map.borrow() let method_ty = ccx.tcx.method_map.borrow()
.find(&method_call).map(|method| method.ty); .find(&method_call).map(|method| method.ty);
let datum = match 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 // converts from the `Shaht<T>` pointer that we have into
// a `&T` pointer. We can then proceed down the normal // a `&T` pointer. We can then proceed down the normal
// path (below) to dereference that `&T`. // path (below) to dereference that `&T`.
let datum = if derefs == 0 { let datum = match method_call.adjustment {
datum // Always perform an AutoPtr when applying an overloaded auto-deref
} else { typeck::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)),
// Always perform an AutoPtr when applying an overloaded auto-deref. _ => datum
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
}; };
let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, let val = unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
datum, None, None)); datum, None, None));
@ -1834,8 +1830,8 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
} }
}; };
debug!("deref_once(expr={}, derefs={}, result={})", debug!("deref_once(expr={}, method_call={}, result={})",
expr.id, derefs, r.datum.to_str(ccx)); expr.id, method_call, r.datum.to_str(ccx));
return r; return r;

View File

@ -538,9 +538,13 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
// Store the vtable into the second half of pair. // Store the vtable into the second half of pair.
let origins = { let origins = {
let vtable_map = ccx.tcx.vtable_map.borrow(); let vtable_map = ccx.tcx.vtable_map.borrow();
resolve_param_vtables_under_param_substs(ccx.tcx(), // This trait cast might be because of implicit coercion
bcx.fcx.param_substs, let method_call = match ccx.tcx.adjustments.borrow().find(&id) {
vtable_map.get(&MethodCall::expr(id)).get_self().unwrap()) 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 vtable = get_vtable(bcx, v_ty, origins);
let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]);

View File

@ -2823,7 +2823,7 @@ pub fn adjust_ty(cx: &ctxt,
if !ty::type_is_error(adjusted_ty) { if !ty::type_is_error(adjusted_ty) {
for i in range(0, adj.autoderefs) { 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) { match method_type(method_call) {
Some(method_ty) => { Some(method_ty) => {
adjusted_ty = ty_fn_ret(method_ty); adjusted_ty = ty_fn_ret(method_ty);

View File

@ -1331,8 +1331,7 @@ pub fn autoderef<T>(fcx: &FnCtxt, sp: Span, base_ty: ty::t,
let mt = match ty::deref(resolved_t, false) { let mt = match ty::deref(resolved_t, false) {
Some(mt) => Some(mt), Some(mt) => Some(mt),
None => { None => {
let method_call = let method_call = expr_id.map(|id| MethodCall::autoderef(id, autoderefs));
expr_id.map(|id| MethodCall::autoderef(id, autoderefs as u32));
try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref)
} }
}; };

View File

@ -879,7 +879,7 @@ fn constrain_autoderefs(rcx: &mut Rcx,
rcx.fcx.infcx().ty_to_str(derefd_ty), rcx.fcx.infcx().ty_to_str(derefd_ty),
i, derefs); 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) { derefd_ty = match rcx.fcx.inh.method_map.borrow().find(&method_call) {
Some(method) => { Some(method) => {
// Treat overloaded autoderefs as if an AutoRef adjustment // Treat overloaded autoderefs as if an AutoRef adjustment

View File

@ -529,7 +529,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
let _indent = indenter(); let _indent = indenter();
let cx = fcx.ccx; 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, // Look up vtables for the type we're casting to,
// passing in the source and target type. The source // passing in the source and target type. The source
// must be a pointer type suitable to the object sigil, // 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 { if !is_early {
let mut r = VecPerParamSpace::empty(); let mut r = VecPerParamSpace::empty();
r.push(subst::SelfSpace, vtables); 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 // 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, _) => { ast::ExprCast(ref src, _) => {
debug!("vtable resolution on expr {}", ex.repr(fcx.tcx())); debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
let target_ty = fcx.expr_ty(ex); 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 { match *adjustment {
AutoDerefRef(adj) => { AutoDerefRef(adj) => {
for autoderef in range(0, adj.autoderefs) { 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) { match fcx.inh.method_map.borrow().find(&method_call) {
Some(method) => { Some(method) => {
debug!("vtable resolution on parameter bounds for autoderef {}", 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(..) => {} AutoAddEnv(..) => {}
} }

View File

@ -248,7 +248,7 @@ impl<'cx> WritebackCx<'cx> {
ty::AutoDerefRef(adj) => { ty::AutoDerefRef(adj) => {
for autoderef in range(0, adj.autoderefs) { 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_method_map_entry(reason, method_call);
self.visit_vtable_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) => { 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( ty::AutoObject(
self.resolve(&trait_store, reason), self.resolve(&trait_store, reason),
self.resolve(&bb, reason), self.resolve(&bb, reason),

View File

@ -149,24 +149,52 @@ pub struct MethodCallee {
pub substs: subst::Substs 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)] #[deriving(Clone, PartialEq, Eq, Hash, Show)]
pub struct MethodCall { pub struct MethodCall {
pub expr_id: ast::NodeId, 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 { impl MethodCall {
pub fn expr(id: ast::NodeId) -> MethodCall { pub fn expr(id: ast::NodeId) -> MethodCall {
MethodCall { MethodCall {
expr_id: id, 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 { MethodCall {
expr_id: expr_id, expr_id: expr_id,
autoderef: 1 + autoderef adjustment: AutoDeref(1 + autoderef)
} }
} }
} }

View File

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

View File

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