librustc: Implement explicit @self and ~self for objects. r=nmatsakis
This commit is contained in:
parent
3afd6c3d79
commit
54ae377ec2
@ -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) */
|
||||
})
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
|
24
src/test/run-pass/explicit-self-objects-box.rs
Normal file
24
src/test/run-pass/explicit-self-objects-box.rs
Normal 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();
|
||||
}
|
||||
|
||||
|
23
src/test/run-pass/explicit-self-objects-uniq.rs
Normal file
23
src/test/run-pass/explicit-self-objects-uniq.rs
Normal 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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user