Skip to content

Commit 54ae377

Browse files
committed
librustc: Implement explicit @self and ~self for objects. r=nmatsakis
1 parent 3afd6c3 commit 54ae377

File tree

4 files changed

+149
-27
lines changed

4 files changed

+149
-27
lines changed

src/librustc/middle/trans/meth.rs

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -546,40 +546,85 @@ fn trans_trait_callee_from_llval(bcx: block,
546546
let mut llself;
547547
debug!("(translating trait callee) loading second index from pair");
548548
let llbox = Load(bcx, GEPi(bcx, llpair, [0u, 1u]));
549-
match vstore {
550-
ty::vstore_box | ty::vstore_uniq => {
551-
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
552-
}
553-
ty::vstore_slice(_) => {
554-
llself = llbox;
555-
}
556-
ty::vstore_fixed(*) => {
557-
bcx.tcx().sess.bug(~"vstore_fixed trait");
558-
}
559-
}
560549
561550
// Munge `llself` appropriately for the type of `self` in the method.
551+
let self_mode;
562552
match explicit_self {
563553
ast::sty_static => {
564554
bcx.tcx().sess.bug(~"shouldn't see static method here");
565555
}
566-
ast::sty_by_ref => {} // Nothing to do.
556+
ast::sty_by_ref => {
557+
// We need to pass a pointer to a pointer to the payload.
558+
match vstore {
559+
ty::vstore_box | ty::vstore_uniq => {
560+
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
561+
}
562+
ty::vstore_slice(_) => {
563+
llself = llbox;
564+
}
565+
ty::vstore_fixed(*) => {
566+
bcx.tcx().sess.bug(~"vstore_fixed trait");
567+
}
568+
}
569+
570+
self_mode = ast::by_ref;
571+
}
567572
ast::sty_value => {
568573
bcx.tcx().sess.bug(~"methods with by-value self should not be \
569574
called on objects");
570575
}
571576
ast::sty_region(_) => {
577+
// As before, we need to pass a pointer to a pointer to the
578+
// payload.
579+
match vstore {
580+
ty::vstore_box | ty::vstore_uniq => {
581+
llself = GEPi(bcx, llbox, [0u, abi::box_field_body]);
582+
}
583+
ty::vstore_slice(_) => {
584+
llself = llbox;
585+
}
586+
ty::vstore_fixed(*) => {
587+
bcx.tcx().sess.bug(~"vstore_fixed trait");
588+
}
589+
}
590+
572591
let llscratch = alloca(bcx, val_ty(llself));
573592
Store(bcx, llself, llscratch);
574593
llself = llscratch;
594+
595+
self_mode = ast::by_ref;
575596
}
576597
ast::sty_box(_) => {
577598
// Bump the reference count on the box.
578599
debug!("(translating trait callee) callee type is `%s`",
579600
bcx.ty_to_str(callee_ty));
580-
bcx = glue::take_ty(bcx, llself, callee_ty);
601+
bcx = glue::take_ty(bcx, llbox, callee_ty);
602+
603+
// Pass a pointer to the box.
604+
match vstore {
605+
ty::vstore_box => llself = llbox,
606+
_ => bcx.tcx().sess.bug(~"@self receiver with non-@Trait")
607+
}
608+
609+
let llscratch = alloca(bcx, val_ty(llself));
610+
Store(bcx, llself, llscratch);
611+
llself = llscratch;
612+
613+
self_mode = ast::by_ref;
614+
}
615+
ast::sty_uniq(_) => {
616+
// Pass the unique pointer.
617+
match vstore {
618+
ty::vstore_uniq => llself = llbox,
619+
_ => bcx.tcx().sess.bug(~"~self receiver with non-~Trait")
620+
}
621+
622+
let llscratch = alloca(bcx, val_ty(llself));
623+
Store(bcx, llself, llscratch);
624+
llself = llscratch;
625+
626+
self_mode = ast::by_ref;
581627
}
582-
ast::sty_uniq(_) => {} // Nothing to do here.
583628
}
584629
585630
// 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,
594639
llfn: mptr,
595640
llself: llself,
596641
self_ty: ty::mk_opaque_box(bcx.tcx()),
597-
self_mode: ast::by_ref, // XXX: is this bogosity?
642+
self_mode: self_mode,
598643
/* XXX: Some(llbox) */
599644
})
600645
};

src/librustc/middle/typeck/check/method.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ struct Candidate {
140140
origin: method_origin,
141141
}
142142

143+
/**
144+
* Whether the self type should be transformed according to the form of
145+
* explicit self provided by the method.
146+
*/
147+
enum TransformTypeFlag {
148+
DontTransformType,
149+
TransformType
150+
}
151+
143152
impl LookupContext {
144153
fn do_lookup(&self, self_ty: ty::t) -> Option<method_map_entry> {
145154
debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)",
@@ -402,7 +411,10 @@ impl LookupContext {
402411

403412
let (rcvr_ty, rcvr_substs) =
404413
self.create_rcvr_ty_and_substs_for_method(
405-
method.self_ty, rcvr_ty, move init_substs);
414+
method.self_ty,
415+
rcvr_ty,
416+
move init_substs,
417+
TransformType);
406418

407419
let cand = Candidate {
408420
rcvr_ty: rcvr_ty,
@@ -461,8 +473,10 @@ impl LookupContext {
461473
let rcvr_substs = {self_ty: Some(self_ty), ..*substs};
462474

463475
let (rcvr_ty, rcvr_substs) =
464-
self.create_rcvr_ty_and_substs_for_method(
465-
method.self_ty, self_ty, move rcvr_substs);
476+
self.create_rcvr_ty_and_substs_for_method(method.self_ty,
477+
self_ty,
478+
move rcvr_substs,
479+
DontTransformType);
466480

467481
self.inherent_candidates.push(Candidate {
468482
rcvr_ty: rcvr_ty,
@@ -490,7 +504,10 @@ impl LookupContext {
490504
let rcvr_substs = { self_ty: Some(self_ty), ..*substs };
491505
let (rcvr_ty, rcvr_substs) =
492506
self.create_rcvr_ty_and_substs_for_method(
493-
method.self_ty, self_ty, move rcvr_substs);
507+
method.self_ty,
508+
self_ty,
509+
move rcvr_substs,
510+
TransformType);
494511

495512
self.inherent_candidates.push(Candidate {
496513
rcvr_ty: rcvr_ty,
@@ -542,7 +559,10 @@ impl LookupContext {
542559

543560
let (impl_ty, impl_substs) =
544561
self.create_rcvr_ty_and_substs_for_method(
545-
method.self_type, impl_ty, move impl_substs);
562+
method.self_type,
563+
impl_ty,
564+
move impl_substs,
565+
TransformType);
546566

547567
candidates.push(Candidate {
548568
rcvr_ty: impl_ty,
@@ -577,7 +597,8 @@ impl LookupContext {
577597
self.create_rcvr_ty_and_substs_for_method(
578598
provided_method_info.method_info.self_type,
579599
self_ty,
580-
dummy_substs);
600+
dummy_substs,
601+
TransformType);
581602

582603
candidates.push(Candidate {
583604
rcvr_ty: impl_ty,
@@ -594,8 +615,9 @@ impl LookupContext {
594615
fn create_rcvr_ty_and_substs_for_method(&self,
595616
self_decl: ast::self_ty_,
596617
self_ty: ty::t,
597-
+self_substs: ty::substs)
598-
-> (ty::t, ty::substs) {
618+
+self_substs: ty::substs,
619+
transform_type: TransformTypeFlag)
620+
-> (ty::t, ty::substs) {
599621
// If the self type includes a region (like &self), we need to
600622
// ensure that the receiver substitutions have a self region.
601623
// If the receiver type does not itself contain borrowed
@@ -624,10 +646,18 @@ impl LookupContext {
624646
}
625647
};
626648

627-
let rcvr_ty =
628-
transform_self_type_for_method(
629-
self.tcx(), rcvr_substs.self_r,
630-
self_ty, self_decl);
649+
let rcvr_ty;
650+
match transform_type {
651+
TransformType => {
652+
rcvr_ty = transform_self_type_for_method(self.tcx(),
653+
rcvr_substs.self_r,
654+
self_ty,
655+
self_decl);
656+
}
657+
DontTransformType => {
658+
rcvr_ty = self_ty;
659+
}
660+
}
631661

632662
(rcvr_ty, rcvr_substs)
633663
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
trait Foo {
2+
fn f(@self);
3+
}
4+
5+
struct S {
6+
x: int
7+
}
8+
9+
impl S : Foo {
10+
fn f(@self) {
11+
assert self.x == 3;
12+
}
13+
}
14+
15+
fn main() {
16+
let x = @S { x: 3 };
17+
let y = x as @Foo;
18+
y.f();
19+
y.f();
20+
y.f();
21+
y.f();
22+
}
23+
24+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
trait Foo {
2+
fn f(~self);
3+
}
4+
5+
struct S {
6+
x: int
7+
}
8+
9+
impl S : Foo {
10+
fn f(~self) {
11+
assert self.x == 3;
12+
}
13+
}
14+
15+
fn main() {
16+
let x = ~S { x: 3 };
17+
let y = x as ~Foo;
18+
y.f();
19+
y.f();
20+
y.f();
21+
}
22+
23+

0 commit comments

Comments
 (0)