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
|
// 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);
|
||||||
}
|
}
|
||||||
|
@ -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) => {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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]);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
|
@ -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(..) => {}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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