Skip to content

Commit

Permalink
librustc: Implement explicit @self and ~self for objects. r=nmatsakis
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed Dec 1, 2012
1 parent 3afd6c3 commit 54ae377
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 27 deletions.
75 changes: 60 additions & 15 deletions src/librustc/middle/trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) */
})
};
Expand Down
54 changes: 42 additions & 12 deletions src/librustc/middle/typeck/check/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
24 changes: 24 additions & 0 deletions src/test/run-pass/explicit-self-objects-box.rs
Original file line number Diff line number Diff line change
@@ -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();
}


23 changes: 23 additions & 0 deletions src/test/run-pass/explicit-self-objects-uniq.rs
Original file line number Diff line number Diff line change
@@ -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();
}


0 comments on commit 54ae377

Please sign in to comment.