librustc: Don't overwrite vtables when coercing to trait object.
This commit is contained in:
parent
5c81a186e9
commit
4eb5d7baf9
@ -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);
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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(..) => {}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
src/test/run-pass/deref-rc.rs
Normal file
16
src/test/run-pass/deref-rc.rs
Normal 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]);
|
||||
}
|
25
src/test/run-pass/issue-14399.rs
Normal file
25
src/test/run-pass/issue-14399.rs
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user