about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-10-15 08:02:21 +0000
committerbors <bors@rust-lang.org>2014-10-15 08:02:21 +0000
commit71dfa5befe2ddf3d16fb5e23f6922125cf1cf5e6 (patch)
tree3d416ef1e7ec6e03930f7de4a281a82b3457cf1d
parent5201bf17e6a051dd1411513346d8efc4afcb3c36 (diff)
parentfe8e591147857a0f5ad10570e7cc3f304e9b2cd2 (diff)
downloadrust-71dfa5befe2ddf3d16fb5e23f6922125cf1cf5e6.tar.gz
rust-71dfa5befe2ddf3d16fb5e23f6922125cf1cf5e6.zip
auto merge of #18053 : nick29581/rust/ufcs1, r=pcwalton
With the 'receiver' as an argument and static dispatch. Part of UFCS implementation (#16293).

r?
-rw-r--r--src/librustc/metadata/encoder.rs22
-rw-r--r--src/librustc/middle/astencode.rs4
-rw-r--r--src/librustc/middle/def.rs4
-rw-r--r--src/librustc/middle/privacy.rs2
-rw-r--r--src/librustc/middle/resolve.rs78
-rw-r--r--src/librustc/middle/save/mod.rs2
-rw-r--r--src/librustc/middle/trans/callee.rs15
-rw-r--r--src/librustc/middle/typeck/check/mod.rs8
-rw-r--r--src/librustc/middle/typeck/collect.rs13
-rw-r--r--src/test/compile-fail/call-extern-trait-as-function.rs17
-rw-r--r--src/test/compile-fail/method-self-arg-1.rs24
-rw-r--r--src/test/compile-fail/method-self-arg-2.rs27
-rw-r--r--src/test/run-pass/method-self-arg-trait.rs75
-rw-r--r--src/test/run-pass/method-self-arg.rs54
14 files changed, 231 insertions, 114 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 02f6a4a78db..009a06f5290 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -407,13 +407,10 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
                         method_did.def_id());
                     match impl_item {
                         ty::MethodTraitItem(ref m) => {
-                            if m.explicit_self ==
-                                    ty::StaticExplicitSelfCategory {
-                                encode_reexported_static_method(rbml_w,
-                                                                exp,
-                                                                m.def_id,
-                                                                m.ident);
-                            }
+                            encode_reexported_static_method(rbml_w,
+                                                            exp,
+                                                            m.def_id,
+                                                            m.ident);
                         }
                         ty::TypeTraitItem(_) => {}
                     }
@@ -434,8 +431,7 @@ fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
         Some(trait_items) => {
             for trait_item in trait_items.iter() {
                 match *trait_item {
-                    ty::MethodTraitItem(ref m) if m.explicit_self ==
-                            ty::StaticExplicitSelfCategory => {
+                    ty::MethodTraitItem(ref m) => {
                         encode_reexported_static_method(rbml_w,
                                                         exp,
                                                         m.def_id,
@@ -1408,18 +1404,16 @@ fn encode_info_for_item(ecx: &EncodeContext,
                             encode_family(rbml_w,
                                           fn_style_static_method_family(
                                               method_ty.fty.fn_style));
-
-                            let pty = ty::lookup_item_type(tcx,
-                                                           method_def_id);
-                            encode_bounds_and_type(rbml_w, ecx, &pty);
                         }
-
                         _ => {
                             encode_family(rbml_w,
                                           style_fn_family(
                                               method_ty.fty.fn_style));
                         }
                     }
+                    let pty = ty::lookup_item_type(tcx,
+                                                   method_def_id);
+                    encode_bounds_and_type(rbml_w, ecx, &pty);
 
                     is_nonstatic_method = method_ty.explicit_self !=
                         ty::StaticExplicitSelfCategory;
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 955228c99de..7cadcb745ca 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -453,8 +453,8 @@ impl tr for def::Def {
                                    },
                                    p)
           }
-          def::DefMethod(did0, did1) => {
-            def::DefMethod(did0.tr(dcx), did1.map(|did1| did1.tr(dcx)))
+          def::DefMethod(did0, did1, p) => {
+            def::DefMethod(did0.tr(dcx), did1.map(|did1| did1.tr(dcx)), p)
           }
           def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) }
           def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs
index 3b7af9788ac..3facf0b0c0a 100644
--- a/src/librustc/middle/def.rs
+++ b/src/librustc/middle/def.rs
@@ -46,7 +46,7 @@ pub enum Def {
     DefTyParamBinder(ast::NodeId), /* struct, impl or trait with ty params */
     DefRegion(ast::NodeId),
     DefLabel(ast::NodeId),
-    DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */),
+    DefMethod(ast::DefId /* method */, Option<ast::DefId> /* trait */, MethodProvenance),
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
@@ -62,7 +62,7 @@ impl Def {
             DefForeignMod(id) | DefStatic(id, _) |
             DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
             DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
-            DefMethod(id, _) | DefConst(id) => {
+            DefMethod(id, _, _) | DefConst(id) => {
                 id
             }
             DefLocal(id) |
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index e434d859993..8b9207134ea 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -811,7 +811,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             def::DefTy(_, true) => ck("enum"),
             def::DefTrait(..) => ck("trait"),
             def::DefStruct(..) => ck("struct"),
-            def::DefMethod(_, Some(..)) => ck("trait method"),
+            def::DefMethod(_, Some(..), _) => ck("trait method"),
             def::DefMethod(..) => ck("method"),
             def::DefMod(..) => ck("module"),
             _ => {}
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 06ebd70977f..a53cd52ca84 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -250,7 +250,7 @@ enum FallbackSuggestion {
     Method,
     TraitItem,
     StaticMethod(String),
-    StaticTraitMethod(String),
+    TraitMethod(String),
 }
 
 enum TypeParameters<'a> {
@@ -1386,17 +1386,17 @@ impl<'a> Resolver<'a> {
                                                           .node {
                                         SelfStatic => {
                                             // Static methods become
-                                            // `def_static_method`s.
-                                            DefStaticMethod(
-                                                local_def(method.id),
-                                                FromImpl(local_def(item.id)),
-                                                         method.pe_fn_style())
+                                            // `DefStaticMethod`s.
+                                            DefStaticMethod(local_def(method.id),
+                                                            FromImpl(local_def(item.id)),
+                                                                     method.pe_fn_style())
                                         }
                                         _ => {
                                             // Non-static methods become
-                                            // `def_method`s.
+                                            // `DefMethod`s.
                                             DefMethod(local_def(method.id),
-                                                      None)
+                                                      None,
+                                                      FromImpl(local_def(item.id)))
                                         }
                                     };
 
@@ -1476,8 +1476,7 @@ impl<'a> Resolver<'a> {
                             let (def, static_flag) = match ty_m.explicit_self
                                                                .node {
                                 SelfStatic => {
-                                    // Static methods become
-                                    // `def_static_method`s.
+                                    // Static methods become `DefStaticMethod`s.
                                     (DefStaticMethod(
                                             local_def(ty_m.id),
                                             FromTrait(local_def(item.id)),
@@ -1485,10 +1484,10 @@ impl<'a> Resolver<'a> {
                                      StaticMethodTraitItemKind)
                                 }
                                 _ => {
-                                    // Non-static methods become
-                                    // `def_method`s.
+                                    // Non-static methods become `DefMethod`s.
                                     (DefMethod(local_def(ty_m.id),
-                                               Some(local_def(item.id))),
+                                               Some(local_def(item.id)),
+                                               FromTrait(local_def(item.id))),
                                      NonstaticMethodTraitItemKind)
                                 }
                             };
@@ -4607,8 +4606,7 @@ impl<'a> Resolver<'a> {
                                 // We also need a new scope for the method-
                                 // specific type parameters.
                                 this.resolve_method(
-                                    MethodRibKind(id,
-                                                  ProvidedMethod(method.id)),
+                                    MethodRibKind(id, ProvidedMethod(method.id)),
                                     &**method);
                             }
                             TypeImplItem(ref typedef) => {
@@ -5393,8 +5391,8 @@ impl<'a> Resolver<'a> {
 
         let ident = path.segments.last().unwrap().identifier;
         let def = match self.resolve_definition_of_name_in_module(containing_module.clone(),
-                                                        ident.name,
-                                                        namespace) {
+                                                                  ident.name,
+                                                                  namespace) {
             NoNameDefinition => {
                 // We failed to resolve the name. Report an error.
                 return None;
@@ -5403,26 +5401,6 @@ impl<'a> Resolver<'a> {
                 (def, last_private.or(lp))
             }
         };
-        match containing_module.kind.get() {
-            TraitModuleKind | ImplModuleKind => {
-                match containing_module.def_id.get() {
-                    Some(def_id) => {
-                        match self.trait_item_map.find(&(ident.name, def_id)) {
-                            Some(&StaticMethodTraitItemKind) => (),
-                            Some(&TypeTraitItemKind) => (),
-                            None => (),
-                            Some(&NonstaticMethodTraitItemKind) => {
-                                debug!("containing module was a trait or impl \
-                                and name was a method -> not resolved");
-                                return None;
-                            }
-                        }
-                    },
-                    _ => (),
-                }
-            },
-            _ => (),
-        }
         match containing_module.def_id.get() {
             Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
             _ => {}
@@ -5668,8 +5646,8 @@ impl<'a> Resolver<'a> {
                                 FromTrait(_) => unreachable!()
                             }
                         }
-                        Some(DefMethod(_, None)) if allowed == Everything => return Method,
-                        Some(DefMethod(_, Some(_))) => return TraitItem,
+                        Some(DefMethod(_, None, _)) if allowed == Everything => return Method,
+                        Some(DefMethod(_, Some(_), _)) => return TraitItem,
                         _ => ()
                     }
                 }
@@ -5684,7 +5662,9 @@ impl<'a> Resolver<'a> {
                 let path_str = self.path_idents_to_string(&trait_ref.path);
 
                 match self.trait_item_map.find(&(name, did)) {
-                    Some(&StaticMethodTraitItemKind) => return StaticTraitMethod(path_str),
+                    Some(&StaticMethodTraitItemKind) => {
+                        return TraitMethod(path_str)
+                    }
                     Some(_) => return TraitItem,
                     None => {}
                 }
@@ -5751,22 +5731,6 @@ impl<'a> Resolver<'a> {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `{}`",
                                self.path_idents_to_string(path));
-
-                        // First-class methods are not supported yet; error
-                        // out here.
-                        match def {
-                            (DefMethod(..), _) => {
-                                self.resolve_error(expr.span,
-                                                      "first-class methods \
-                                                       are not supported");
-                                self.session.span_note(expr.span,
-                                                       "call the method \
-                                                        using the `.` \
-                                                        syntax");
-                            }
-                            _ => {}
-                        }
-
                         self.record_def(expr.id, def);
                     }
                     None => {
@@ -5826,7 +5790,7 @@ impl<'a> Resolver<'a> {
                                         Method
                                         | TraitItem =>
                                             format!("to call `self.{}`", wrong_name),
-                                        StaticTraitMethod(path_str)
+                                        TraitMethod(path_str)
                                         | StaticMethod(path_str) =>
                                             format!("to call `{}::{}`", path_str, wrong_name)
                                     };
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index 4aba29d7bae..21810b608b4 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -244,7 +244,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
             def::DefStaticMethod(_, _, _) |
             def::DefTyParam(..) |
             def::DefUse(_) |
-            def::DefMethod(_, _) |
+            def::DefMethod(..) |
             def::DefPrimTy(_) => {
                 self.sess.span_bug(span, format!("lookup_def_kind for unexpected item: {:?}",
                                                  def).as_slice());
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 1b23841c913..bb32fdcea7e 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -137,7 +137,9 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
         };
     }
 
-    fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: def::Def, ref_expr: &ast::Expr)
+    fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                             def: def::Def,
+                             ref_expr: &ast::Expr)
                              -> Callee<'blk, 'tcx> {
         debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
         let expr_ty = node_id_type(bcx, ref_expr.id);
@@ -165,14 +167,13 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                 let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
                 Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
             }
-            def::DefFn(did, _, _) |
+            def::DefFn(did, _, _) | def::DefMethod(did, _, def::FromImpl(_)) |
             def::DefStaticMethod(did, def::FromImpl(_), _) => {
                 fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id)))
             }
-            def::DefStaticMethod(impl_did,
-                                 def::FromTrait(trait_did),
-                                 _) => {
-                fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
+            def::DefStaticMethod(meth_did, def::FromTrait(trait_did), _) |
+            def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => {
+                fn_callee(bcx, meth::trans_static_method_callee(bcx, meth_did,
                                                                 trait_did,
                                                                 ref_expr.id))
             }
@@ -205,7 +206,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
             def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
             def::DefUse(..) | def::DefTyParamBinder(..) |
             def::DefRegion(..) | def::DefLabel(..) | def::DefTyParam(..) |
-            def::DefSelfTy(..) | def::DefMethod(..) => {
+            def::DefSelfTy(..) => {
                 bcx.tcx().sess.span_bug(
                     ref_expr.span,
                     format!("cannot translate def {:?} \
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index b78398fdb6d..d88e01f6e49 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -5027,7 +5027,7 @@ pub fn polytype_for_def(fcx: &FnCtxt,
           let typ = fcx.local_ty(sp, nid);
           return no_params(typ);
       }
-      def::DefFn(id, _, _) | def::DefStaticMethod(id, _, _) |
+      def::DefFn(id, _, _) | def::DefStaticMethod(id, _, _) | def::DefMethod(id, _, _) |
       def::DefStatic(id, _) | def::DefVariant(_, id, _) |
       def::DefStruct(id) | def::DefConst(id) => {
         return ty::lookup_item_type(fcx.ccx.tcx, id);
@@ -5057,9 +5057,6 @@ pub fn polytype_for_def(fcx: &FnCtxt,
       def::DefSelfTy(..) => {
         fcx.ccx.tcx.sess.span_bug(sp, "expected value, found self ty");
       }
-      def::DefMethod(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found method");
-      }
     }
 }
 
@@ -5231,8 +5228,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
     }
 
     fcx.add_obligations_for_parameters(
-        traits::ObligationCause::new(span,
-                                     traits::ItemObligation(def.def_id())),
+        traits::ObligationCause::new(span, traits::ItemObligation(def.def_id())),
         &substs,
         &polytype.generics);
 
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 100dffb547b..6e25b23daac 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -77,10 +77,12 @@ pub fn collect_item_types(ccx: &CrateCtxt) {
     }
 
     match ccx.tcx.lang_items.ty_desc() {
-        Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
+        Some(id) => { collect_intrinsic_type(ccx, id); }
+        None => {}
     }
     match ccx.tcx.lang_items.opaque() {
-        Some(id) => { collect_intrinsic_type(ccx, id); } None => {}
+        Some(id) => { collect_intrinsic_type(ccx, id); }
+        None => {}
     }
 
     let mut visitor = CollectTraitDefVisitor{ ccx: ccx };
@@ -306,10 +308,7 @@ fn collect_trait_methods(ccx: &CrateCtxt,
                                     }
                                 });
 
-                                if ty_method.explicit_self ==
-                                        ty::StaticExplicitSelfCategory {
-                                    make_static_method_ty(ccx, &*ty_method);
-                                }
+                                make_method_ty(ccx, &*ty_method);
 
                                 tcx.impl_or_trait_items
                                    .borrow_mut()
@@ -364,7 +363,7 @@ fn collect_trait_methods(ccx: &CrateCtxt,
         _ => { /* Ignore things that aren't traits */ }
     }
 
-    fn make_static_method_ty(ccx: &CrateCtxt, m: &ty::Method) {
+    fn make_method_ty(ccx: &CrateCtxt, m: &ty::Method) {
         ccx.tcx.tcache.borrow_mut().insert(
             m.def_id,
             Polytype {
diff --git a/src/test/compile-fail/call-extern-trait-as-function.rs b/src/test/compile-fail/call-extern-trait-as-function.rs
deleted file mode 100644
index 86ebeedda67..00000000000
--- a/src/test/compile-fail/call-extern-trait-as-function.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// issue #6698
-
-fn V() -> bool {
-    std::clone::Clone::clone(true) //~ ERROR error: unresolved name `std::clone::Clone::clone`.
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/method-self-arg-1.rs b/src/test/compile-fail/method-self-arg-1.rs
new file mode 100644
index 00000000000..82d75b45394
--- /dev/null
+++ b/src/test/compile-fail/method-self-arg-1.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test method calls with self as an argument cannot subvert type checking.
+
+struct Foo;
+
+impl Foo {
+    fn bar(&self) {}
+}
+
+fn main() {
+    let x = Foo;
+    Foo::bar(x); //~ERROR mismatched types: expected `&Foo`, found `Foo`
+    Foo::bar(&&x); //~ERROR mismatched types: expected `&Foo`, found `&&Foo`
+    Foo::bar(&42i); //~ERROR mismatched types: expected `&Foo`, found `&int`
+}
diff --git a/src/test/compile-fail/method-self-arg-2.rs b/src/test/compile-fail/method-self-arg-2.rs
new file mode 100644
index 00000000000..0ac0851619c
--- /dev/null
+++ b/src/test/compile-fail/method-self-arg-2.rs
@@ -0,0 +1,27 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test method calls with self as an argument cannot subvert borrow checking.
+
+struct Foo;
+
+impl Foo {
+    fn bar(&self) {}
+    fn baz(&mut self) {}
+}
+
+fn main() {
+    let mut x = Foo;
+    let y = &mut x;
+    Foo::bar(&x); //~ERROR cannot borrow `x`
+
+    let x = Foo;
+    Foo::baz(&x); //~ERROR cannot borrow immutable dereference of `&`-pointer as mutable
+}
diff --git a/src/test/run-pass/method-self-arg-trait.rs b/src/test/run-pass/method-self-arg-trait.rs
new file mode 100644
index 00000000000..b821c064cac
--- /dev/null
+++ b/src/test/run-pass/method-self-arg-trait.rs
@@ -0,0 +1,75 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test method calls with self as an argument
+
+static mut COUNT: u64 = 1;
+
+struct Foo;
+
+trait Bar {
+    fn foo1(&self);
+    fn foo2(self);
+    fn foo3(self: Box<Self>);
+
+    fn bar1(&self) {
+        unsafe { COUNT *= 7; }
+    }
+    fn bar2(self) {
+        unsafe { COUNT *= 11; }
+    }
+    fn bar3(self: Box<Self>) {
+        unsafe { COUNT *= 13; }
+    }
+}
+
+impl Bar for Foo {
+    fn foo1(&self) {
+        unsafe { COUNT *= 2; }
+    }
+
+    fn foo2(self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    fn foo3(self: Box<Foo>) {
+        unsafe { COUNT *= 5; }
+    }
+}
+
+impl Foo {
+    fn baz(self) {
+        unsafe { COUNT *= 17; }
+        // Test internal call.
+        Bar::foo1(&self);
+        Bar::foo2(self);
+        Bar::foo3(box self);
+
+        Bar::bar1(&self);
+        Bar::bar2(self);
+        Bar::bar3(box self);
+    }
+}
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Bar::foo1(&x);
+    Bar::foo2(x);
+    Bar::foo3(box x);
+
+    Bar::bar1(&x);
+    Bar::bar2(x);
+    Bar::bar3(box x);
+
+    x.baz();
+
+    unsafe { assert!(COUNT == 2u64*2*3*3*5*5*7*7*11*11*13*13*17); }
+}
diff --git a/src/test/run-pass/method-self-arg.rs b/src/test/run-pass/method-self-arg.rs
new file mode 100644
index 00000000000..3d73f34f8cf
--- /dev/null
+++ b/src/test/run-pass/method-self-arg.rs
@@ -0,0 +1,54 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test method calls with self as an argument
+
+static mut COUNT: uint = 1;
+
+struct Foo;
+
+impl Foo {
+    fn foo(self, x: &Foo) {
+        unsafe { COUNT *= 2; }
+        // Test internal call.
+        Foo::bar(&self);
+        Foo::bar(x);
+
+        Foo::baz(self);
+        Foo::baz(*x);
+
+        Foo::qux(box self);
+        Foo::qux(box *x);
+    }
+
+    fn bar(&self) {
+        unsafe { COUNT *= 3; }
+    }
+
+    fn baz(self) {
+        unsafe { COUNT *= 5; }
+    }
+
+    fn qux(self: Box<Foo>) {
+        unsafe { COUNT *= 7; }
+    }
+}
+
+fn main() {
+    let x = Foo;
+    // Test external call.
+    Foo::bar(&x);
+    Foo::baz(x);
+    Foo::qux(box x);
+
+    x.foo(&x);
+
+    unsafe { assert!(COUNT == 2u*3*3*3*5*5*5*7*7*7); }
+}