]> git.lizzy.rs Git - rust.git/commitdiff
librustc: Implement explicit @self and ~self for objects. r=nmatsakis
authorPatrick Walton <pcwalton@mimiga.net>
Thu, 29 Nov 2012 18:59:49 +0000 (10:59 -0800)
committerPatrick Walton <pcwalton@mimiga.net>
Sat, 1 Dec 2012 03:39:01 +0000 (19:39 -0800)
src/librustc/middle/trans/meth.rs
src/librustc/middle/typeck/check/method.rs
src/test/run-pass/explicit-self-objects-box.rs [new file with mode: 0644]
src/test/run-pass/explicit-self-objects-uniq.rs [new file with mode: 0644]

index 226c076fd0a3d9f60f1eab0d71e03029041be4fd..c8776741c79ef4e313f407ea469fecc36bf0f400 100644 (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) */
         })
     };
index 0ffc321977f946493d139e83aa1e695f406958d0..43292f20e79248ef73c8215bd666b68749cf0f9a 100644 (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 @@ fn push_inherent_candidates_from_param(&self, rcvr_ty: ty::t,
 
                 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 @@ fn push_inherent_candidates_from_trait(&self,
         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 @@ fn push_inherent_candidates_from_self(&self,
         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 @@ fn push_candidates_from_impl(&self, candidates: &DVec<Candidate>,
 
         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 @@ fn push_candidates_from_provided_methods(
                 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 @@ fn push_candidates_from_provided_methods(
     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 @@ fn create_rcvr_ty_and_substs_for_method(&self,
             }
         };
 
-        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 (file)
index 0000000..6ada89b
--- /dev/null
@@ -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 (file)
index 0000000..26b2f4b
--- /dev/null
@@ -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();
+}
+
+