diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 226c076fd0a..c8776741c79 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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) */ }) }; diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 0ffc321977f..43292f20e79 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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 { 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) } diff --git a/src/test/run-pass/explicit-self-objects-box.rs b/src/test/run-pass/explicit-self-objects-box.rs new file mode 100644 index 00000000000..6ada89b1e67 --- /dev/null +++ b/src/test/run-pass/explicit-self-objects-box.rs @@ -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(); +} + + diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs new file mode 100644 index 00000000000..26b2f4b8309 --- /dev/null +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -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(); +} + +