librustc: Implement explicit @self and ~self for objects. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-11-29 10:59:49 -08:00
parent 3afd6c3d79
commit 54ae377ec2
4 changed files with 149 additions and 27 deletions

View File

@ -546,40 +546,85 @@ fn trans_trait_callee_from_llval(bcx: block,
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]);
}
ty::vstore_slice(_) => {
llself = llbox;
}
ty::vstore_fixed(*) => {
bcx.tcx().sess.bug(~"vstore_fixed trait");
}
}
// 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 => {} // Nothing to do.
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;
}
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, llself, 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;
}
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;
}
ast::sty_uniq(_) => {} // Nothing to do here.
}
// Load the function from the vtable and cast it to the expected type.
@ -594,7 +639,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) */
})
};

View File

@ -140,6 +140,15 @@ struct Candidate {
origin: method_origin,
}
/**
* Whether the self type should be transformed according to the form of
* explicit self provided by the method.
*/
enum TransformTypeFlag {
DontTransformType,
TransformType
}
impl LookupContext {
fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)",
@ -402,7 +411,10 @@ impl LookupContext {
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty, rcvr_ty, move init_substs);
method.self_ty,
rcvr_ty,
move init_substs,
TransformType);
let cand = Candidate {
rcvr_ty: rcvr_ty,
@ -461,8 +473,10 @@ impl LookupContext {
let rcvr_substs = {self_ty: Some(self_ty), ..*substs};
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty, self_ty, move rcvr_substs);
self.create_rcvr_ty_and_substs_for_method(method.self_ty,
self_ty,
move rcvr_substs,
DontTransformType);
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
@ -490,7 +504,10 @@ impl LookupContext {
let rcvr_substs = { self_ty: Some(self_ty), ..*substs };
let (rcvr_ty, rcvr_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_ty, self_ty, move rcvr_substs);
method.self_ty,
self_ty,
move rcvr_substs,
TransformType);
self.inherent_candidates.push(Candidate {
rcvr_ty: rcvr_ty,
@ -542,7 +559,10 @@ impl LookupContext {
let (impl_ty, impl_substs) =
self.create_rcvr_ty_and_substs_for_method(
method.self_type, impl_ty, move impl_substs);
method.self_type,
impl_ty,
move impl_substs,
TransformType);
candidates.push(Candidate {
rcvr_ty: impl_ty,
@ -577,7 +597,8 @@ impl LookupContext {
self.create_rcvr_ty_and_substs_for_method(
provided_method_info.method_info.self_type,
self_ty,
dummy_substs);
dummy_substs,
TransformType);
candidates.push(Candidate {
rcvr_ty: impl_ty,
@ -594,8 +615,9 @@ impl LookupContext {
fn create_rcvr_ty_and_substs_for_method(&self,
self_decl: ast::self_ty_,
self_ty: ty::t,
+self_substs: ty::substs)
-> (ty::t, ty::substs) {
+self_substs: ty::substs,
transform_type: TransformTypeFlag)
-> (ty::t, ty::substs) {
// If the self type includes a region (like &self), we need to
// ensure that the receiver substitutions have a self region.
// If the receiver type does not itself contain borrowed
@ -624,10 +646,18 @@ impl LookupContext {
}
};
let rcvr_ty =
transform_self_type_for_method(
self.tcx(), rcvr_substs.self_r,
self_ty, self_decl);
let rcvr_ty;
match transform_type {
TransformType => {
rcvr_ty = transform_self_type_for_method(self.tcx(),
rcvr_substs.self_r,
self_ty,
self_decl);
}
DontTransformType => {
rcvr_ty = self_ty;
}
}
(rcvr_ty, rcvr_substs)
}

View File

@ -0,0 +1,24 @@
trait Foo {
fn f(@self);
}
struct S {
x: int
}
impl S : Foo {
fn f(@self) {
assert self.x == 3;
}
}
fn main() {
let x = @S { x: 3 };
let y = x as @Foo;
y.f();
y.f();
y.f();
y.f();
}

View File

@ -0,0 +1,23 @@
trait Foo {
fn f(~self);
}
struct S {
x: int
}
impl S : Foo {
fn f(~self) {
assert self.x == 3;
}
}
fn main() {
let x = ~S { x: 3 };
let y = x as ~Foo;
y.f();
y.f();
y.f();
}