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: Implement explicit self for objects #4068

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 1 addition & 1 deletion src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub trait Owned {

#[lang="drop"]
pub trait Drop {
fn finalize(); // XXX: Rename to "drop"? --pcwalton
fn finalize(&self); // XXX: Rename to "drop"? --pcwalton
}

#[lang="add"]
Expand Down
8 changes: 8 additions & 0 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ fn serialize_method_map_entry(ecx: @e::encode_ctxt,
do ebml_w.emit_field(~"self_arg", 0u) {
ebml_w.emit_arg(ecx, mme.self_arg);
}
do ebml_w.emit_field(~"explicit_self", 2u) {
mme.explicit_self.serialize(&ebml_w);
}
do ebml_w.emit_field(~"origin", 1u) {
mme.origin.serialize(&ebml_w);
}
Expand All @@ -456,6 +459,11 @@ impl Reader::Deserializer: read_method_map_entry_helper {
self.read_field(~"self_arg", 0u, || {
self.read_arg(xcx)
}),
explicit_self:
self.read_field(~"explicit_self", 2u, || {
let self_type: ast::self_ty_ = deserialize(&self);
self_type
}),
origin:
self.read_field(~"origin", 1u, || {
let method_origin: method_origin = deserialize(&self);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ fn with_field_tys<R>(tcx: ty::ctxt,
}

ty::ty_class(did, ref substs) => {
let has_dtor = ty::ty_dtor(tcx, did).is_some();
let has_dtor = ty::ty_dtor(tcx, did).is_present();
op(has_dtor, class_items_as_mutable_fields(tcx, did, substs))
}

Expand Down
35 changes: 28 additions & 7 deletions src/librustc/middle/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,14 @@ fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
}
ty::ty_class(did, ref substs) => {
// Call the dtor if there is one
do option::map_default(&ty::ty_dtor(bcx.tcx(), did), bcx) |dt_id| {
trans_class_drop(bcx, v, *dt_id, did, substs)
match ty::ty_dtor(bcx.tcx(), did) {
ty::NoDtor => bcx,
ty::LegacyDtor(ref dt_id) => {
trans_class_drop(bcx, v, *dt_id, did, substs, false)
}
ty::TraitDtor(ref dt_id) => {
trans_class_drop(bcx, v, *dt_id, did, substs, true)
}
}
}
_ => bcx
Expand All @@ -410,7 +416,8 @@ fn trans_class_drop(bcx: block,
v0: ValueRef,
dtor_did: ast::def_id,
class_did: ast::def_id,
substs: &ty::substs) -> block {
substs: &ty::substs,
take_ref: bool) -> block {
let drop_flag = GEPi(bcx, v0, struct_dtor());
do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| {
let mut bcx = cx;
Expand All @@ -427,7 +434,18 @@ fn trans_class_drop(bcx: block,
// just consist of the output pointer and the environment
// (self)
assert(params.len() == 2);
let self_arg = PointerCast(bcx, v0, params[1]);

// If we need to take a reference to the class (because it's using
// the Drop trait), do so now.
let llval;
if take_ref {
llval = alloca(bcx, val_ty(v0));
Store(bcx, v0, llval);
} else {
llval = v0;
}

let self_arg = PointerCast(bcx, llval, params[1]);
let args = ~[bcx.fcx.llretptr, self_arg];
Call(bcx, dtor_addr, args);

Expand Down Expand Up @@ -465,10 +483,13 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
ty::ty_class(did, ref substs) => {
let tcx = bcx.tcx();
match ty::ty_dtor(tcx, did) {
Some(dtor) => {
trans_class_drop(bcx, v0, dtor, did, substs)
ty::TraitDtor(dtor) => {
trans_class_drop(bcx, v0, dtor, did, substs, true)
}
None => {
ty::LegacyDtor(dtor) => {
trans_class_drop(bcx, v0, dtor, did, substs, false)
}
ty::NoDtor => {
// No dtor? Just the default case
iter_structural_ty(bcx, v0, t, drop_ty)
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn simplify_type(tcx: ty::ctxt, typ: ty::t) -> ty::t {
// Reduce a class type to a record type in which all the fields are
// simplified
ty::ty_class(did, ref substs) => {
let simpl_fields = (if ty::ty_dtor(tcx, did).is_some() {
let simpl_fields = (if ty::ty_dtor(tcx, did).is_present() {
// remember the drop flag
~[{ident: syntax::parse::token::special_idents::dtor,
mt: {ty: ty::mk_u8(tcx),
Expand Down
126 changes: 110 additions & 16 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,12 @@ fn trans_method_callee(bcx: block, callee_id: ast::node_id,
}
}
typeck::method_trait(_, off, vstore) => {
trans_trait_callee(bcx, callee_id, off, self, vstore)
trans_trait_callee(bcx,
callee_id,
off,
self,
vstore,
mentry.explicit_self)
}
typeck::method_self(*) => {
fail ~"method_self should have been handled above"
Expand Down Expand Up @@ -388,7 +393,12 @@ fn trans_monomorphized_callee(bcx: block,
}
}
typeck::vtable_trait(_, _) => {
trans_trait_callee(bcx, callee_id, n_method, base, ty::vstore_box)
trans_trait_callee(bcx,
callee_id,
n_method,
base,
ty::vstore_box,
mentry.explicit_self)
}
typeck::vtable_param(*) => {
fail ~"vtable_param left in monomorphized function's vtable substs";
Expand Down Expand Up @@ -490,8 +500,9 @@ fn trans_trait_callee(bcx: block,
callee_id: ast::node_id,
n_method: uint,
self_expr: @ast::expr,
vstore: ty::vstore)
-> Callee
vstore: ty::vstore,
explicit_self: ast::self_ty_)
-> Callee
{
//!
//
Expand All @@ -507,15 +518,21 @@ fn trans_trait_callee(bcx: block,
let self_datum = unpack_datum!(bcx, expr::trans_to_datum(bcx, self_expr));
let llpair = self_datum.to_ref_llval(bcx);
let callee_ty = node_id_type(bcx, callee_id);
trans_trait_callee_from_llval(bcx, callee_ty, n_method, llpair, vstore)
trans_trait_callee_from_llval(bcx,
callee_ty,
n_method,
llpair,
vstore,
explicit_self)
}

fn trans_trait_callee_from_llval(bcx: block,
callee_ty: ty::t,
n_method: uint,
llpair: ValueRef,
vstore: ty::vstore)
-> Callee
vstore: ty::vstore,
explicit_self: ast::self_ty_)
-> Callee
{
//!
//
Expand All @@ -527,28 +544,101 @@ fn trans_trait_callee_from_llval(bcx: block,
let mut bcx = bcx;

// Load the vtable from the @Trait pair
debug!("(translating trait callee) loading vtable from pair %s",
val_str(bcx.ccx().tn, llpair));
let llvtable = Load(bcx,
PointerCast(bcx,
GEPi(bcx, llpair, [0u, 0u]),
T_ptr(T_ptr(T_vtable()))));

// Load the box from the @Trait pair and GEP over the box header if
// necessary:
let llself;
let mut llself;
debug!("(translating trait callee) loading second index from pair");
let llbox = Load(bcx, GEPi(bcx, llpair, [0u, 1u]));
match vstore {
ty::vstore_box | ty::vstore_uniq => {
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);

// Munge `llself` appropriately for the type of `self` in the method.
let self_mode;
match explicit_self {
ast::sty_static => {
bcx.tcx().sess.bug(~"shouldn't see static method here");
}
ast::sty_by_ref => {
// We need to pass a pointer to a pointer to the payload.
match vstore {
ty::vstore_box | ty::vstore_uniq => {
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
}
ty::vstore_slice(_) => {
llself = llbox;
}
ty::vstore_fixed(*) => {
bcx.tcx().sess.bug(~"vstore_fixed trait");
}
}

self_mode = ast::by_ref;
}
ast::sty_value => {
bcx.tcx().sess.bug(~"methods with by-value self should not be \
called on objects");
}
ast::sty_region(_) => {
// As before, we need to pass a pointer to a pointer to the
// payload.
match vstore {
ty::vstore_box | ty::vstore_uniq => {
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
}
ty::vstore_slice(_) => {
llself = llbox;
}
ty::vstore_fixed(*) => {
bcx.tcx().sess.bug(~"vstore_fixed trait");
}
}

let llscratch = alloca(bcx, val_ty(llself));
Store(bcx, llself, llscratch);
llself = llscratch;

self_mode = ast::by_ref;
}
ty::vstore_slice(_) => {
llself = llbox;
ast::sty_box(_) => {
// Bump the reference count on the box.
debug!("(translating trait callee) callee type is `%s`",
bcx.ty_to_str(callee_ty));
bcx = glue::take_ty(bcx, llbox, callee_ty);

// Pass a pointer to the box.
match vstore {
ty::vstore_box => llself = llbox,
_ => bcx.tcx().sess.bug(~"@self receiver with non-@Trait")
}

let llscratch = alloca(bcx, val_ty(llself));
Store(bcx, llself, llscratch);
llself = llscratch;

self_mode = ast::by_ref;
}
ty::vstore_fixed(*) => {
bcx.tcx().sess.bug(~"vstore_fixed trait");
ast::sty_uniq(_) => {
// Pass the unique pointer.
match vstore {
ty::vstore_uniq => llself = llbox,
_ => bcx.tcx().sess.bug(~"~self receiver with non-~Trait")
}

let llscratch = alloca(bcx, val_ty(llself));
Store(bcx, llself, llscratch);
llself = llscratch;

self_mode = ast::by_ref;
}
}

// Load the function from the vtable and cast it to the expected type.
debug!("(translating trait callee) loading method");
let llcallee_ty = type_of::type_of_fn_from_ty(ccx, callee_ty);
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method]));
let mptr = PointerCast(bcx, mptr, T_ptr(llcallee_ty));
Expand All @@ -559,7 +649,7 @@ fn trans_trait_callee_from_llval(bcx: block,
llfn: mptr,
llself: llself,
self_ty: ty::mk_opaque_box(bcx.tcx()),
self_mode: ast::by_ref, // XXX: is this bogosity?
self_mode: self_mode,
/* XXX: Some(llbox) */
})
};
Expand Down Expand Up @@ -631,8 +721,12 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t],
make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| {
let fty = ty::subst_tps(tcx, substs, None, ty::mk_fn(tcx, im.fty));
if (*im.tps).len() > 0u || ty::type_has_self(fty) {
debug!("(making impl vtable) method has self or type params: %s",
tcx.sess.str_of(im.ident));
C_null(T_ptr(T_nil()))
} else {
debug!("(making impl vtable) adding method to vtable: %s",
tcx.sess.str_of(im.ident));
let mut m_id = method_with_name(ccx, impl_id, im.ident);
if has_tps {
// If the method is in another crate, need to make an inlined
Expand Down
11 changes: 7 additions & 4 deletions src/librustc/middle/trans/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ impl reflector {
// XXX: Should not be vstore_box!
let bcx = callee::trans_call_inner(
self.bcx, None, mth_ty, bool_ty,
|bcx| meth::trans_trait_callee_from_llval(bcx, mth_ty,
mth_idx, v,
ty::vstore_box),
|bcx| meth::trans_trait_callee_from_llval(bcx,
mth_ty,
mth_idx,
v,
ty::vstore_box,
ast::sty_by_ref),
ArgVals(args), SaveIn(scratch.val), DontAutorefArg);
let result = scratch.to_value_llval(bcx);
let next_bcx = sub_block(bcx, ~"next");
Expand Down Expand Up @@ -307,4 +310,4 @@ fn ast_proto_constant(proto: ast::Proto) -> uint {
ast::ProtoBox => 3u,
ast::ProtoBorrowed => 4u,
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {

// include a byte flag if there is a dtor so that we know when we've
// been dropped
if ty::ty_dtor(cx.tcx, did) != None {
if ty::ty_dtor(cx.tcx, did).is_present() {
common::set_struct_body(llty, ~[T_struct(tys), T_i8()]);
} else {
common::set_struct_body(llty, ~[T_struct(tys)]);
Expand Down
Loading