Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Jun 19, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 47 additions & 23 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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();
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand All @@ -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()
Expand Down Expand Up @@ -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)
})
})
}
Expand All @@ -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);
})
})
}
Expand All @@ -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)
})
})
}
Expand All @@ -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);
})
})
}
}
_ => {}
}

Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
34 changes: 15 additions & 19 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -1737,31 +1737,28 @@ 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 }
}

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 {
Expand All @@ -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));
Expand Down Expand Up @@ -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;

Expand Down
10 changes: 7 additions & 3 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 7 additions & 5 deletions src/librustc/middle/typeck/check/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
_ => ()
}
Expand All @@ -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 {}",
Expand Down Expand Up @@ -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(..) => {}
}
Expand Down
Loading