about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-12 07:31:08 +0000
committerbors <bors@rust-lang.org>2017-11-12 07:31:08 +0000
commitb087dedf3f85c4c90e27cb6e119b4da2712be5c9 (patch)
treed1f64b53857070ed6095261689772904933a1700
parentc1aacdcb30db1cdd32c06fe90cbe38e0800b2502 (diff)
parent77cd993fd1582680cc01ce86d07e52b2e4b34fec (diff)
downloadrust-b087dedf3f85c4c90e27cb6e119b4da2712be5c9.tar.gz
rust-b087dedf3f85c4c90e27cb6e119b4da2712be5c9.zip
Auto merge of #45870 - mikeyhew:arbitrary_self_types, r=arielb1
Implement arbitrary_self_types

r? @arielb1
cc @nikomatsakis

Partial implementation of #44874.  Supports trait and struct methods with arbitrary self types, as long as the type derefs (transitively) to `Self`. Doesn't support raw-pointer `self` yet.

Methods with non-standard self types (i.e. anything other than `&self, &mut self, and Box<Self>`) are not object safe, because dynamic dispatch hasn't been implemented for them yet.

I believe this is also a (partial) fix for #27941.
-rw-r--r--src/librustc/infer/region_inference/mod.rs8
-rw-r--r--src/librustc/traits/object_safety.rs17
-rw-r--r--src/librustc/ty/util.rs53
-rw-r--r--src/librustc_typeck/astconv.rs61
-rw-r--r--src/librustc_typeck/check/compare_method.rs19
-rw-r--r--src/librustc_typeck/check/wfcheck.rs71
-rw-r--r--src/librustc_typeck/diagnostics.rs1
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/compile-fail/arbitrary-self-types-not-object-safe.rs55
-rw-r--r--src/test/compile-fail/feature-gate-arbitrary-self-types.rs27
-rw-r--r--src/test/compile-fail/issue-17740.rs8
-rw-r--r--src/test/compile-fail/issue-26194.rs2
-rw-r--r--src/test/compile-fail/ufcs-explicit-self-bad.rs17
-rw-r--r--src/test/run-pass/arbitrary_self_types_silly.rs (renamed from src/test/compile-fail/E0308-2.rs)17
-rw-r--r--src/test/run-pass/arbitrary_self_types_struct.rs33
-rw-r--r--src/test/run-pass/arbitrary_self_types_trait.rs28
-rw-r--r--src/test/run-pass/arbitrary_self_types_unsized_struct.rs25
-rw-r--r--src/test/ui/span/issue-27522.stderr8
-rw-r--r--src/test/ui/static-lifetime.stderr9
19 files changed, 349 insertions, 113 deletions
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 8351be49076..4c8a72512f1 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -633,11 +633,15 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
         debug!("RegionVarBindings: add_constraint({:?})", constraint);
 
-        if self.constraints.borrow_mut().insert(constraint, origin).is_none() {
+        // never overwrite an existing (constraint, origin) - only insert one if it isn't
+        // present in the map yet. This prevents origins from outside the snapshot being
+        // replaced with "less informative" origins e.g. during calls to `can_eq`
+        self.constraints.borrow_mut().entry(constraint).or_insert_with(|| {
             if self.in_snapshot() {
                 self.undo_log.borrow_mut().push(AddConstraint(constraint));
             }
-        }
+            origin
+        });
     }
 
     fn add_verify(&self, verify: Verify<'tcx>) {
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 1e9816095ea..facd6350e19 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -23,6 +23,7 @@ use hir::def_id::DefId;
 use traits;
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::subst::Substs;
+use ty::util::ExplicitSelf;
 use std::borrow::Cow;
 use syntax::ast;
 
@@ -57,6 +58,10 @@ impl ObjectSafetyViolation {
                          in its arguments or return type", name).into(),
             ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
                 format!("method `{}` has generic type parameters", name).into(),
+            ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) =>
+                format!("method `{}` has a non-standard `self` type. Only `&self`, \
+                        `&mut self`, and `Box<Self>` are currently supported \
+                        for trait objects", name).into(),
             ObjectSafetyViolation::AssociatedConst(name) =>
                 format!("the trait cannot contain associated consts like `{}`", name).into(),
         }
@@ -74,6 +79,9 @@ pub enum MethodViolationCode {
 
     /// e.g., `fn foo<A>()`
     Generic,
+
+    /// arbitrary `self` type, e.g. `self: Rc<Self>`
+    NonStandardSelfType,
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@@ -260,9 +268,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             return Some(MethodViolationCode::StaticMethod);
         }
 
+        let sig = self.fn_sig(method.def_id);
+
+        let self_ty = self.mk_self_type();
+        let self_arg_ty = sig.skip_binder().inputs()[0];
+        if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) {
+            return Some(MethodViolationCode::NonStandardSelfType);
+        }
+
         // The `Self` type is erased, so it should not appear in list of
         // arguments or return type apart from the receiver.
-        let ref sig = self.fn_sig(method.def_id);
         for input_ty in &sig.skip_binder().inputs()[1..] {
             if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
                 return Some(MethodViolationCode::ReferencesSelf);
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 39842a543b5..d12a973017d 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -12,6 +12,7 @@
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
+use hir;
 use ich::NodeIdHashingMode;
 use middle::const_val::ConstVal;
 use traits::{self, Reveal};
@@ -1178,6 +1179,58 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     layout
 }
 
+pub enum ExplicitSelf<'tcx> {
+    ByValue,
+    ByReference(ty::Region<'tcx>, hir::Mutability),
+    ByBox,
+    Other
+}
+
+impl<'tcx> ExplicitSelf<'tcx> {
+    /// Categorizes an explicit self declaration like `self: SomeType`
+    /// into either `self`, `&self`, `&mut self`, `Box<self>`, or
+    /// `Other`.
+    /// This is mainly used to require the arbitrary_self_types feature
+    /// in the case of `Other`, to improve error messages in the common cases,
+    /// and to make `Other` non-object-safe.
+    ///
+    /// Examples:
+    ///
+    /// ```
+    /// impl<'a> Foo for &'a T {
+    ///     // Legal declarations:
+    ///     fn method1(self: &&'a T); // ExplicitSelf::ByReference
+    ///     fn method2(self: &'a T); // ExplicitSelf::ByValue
+    ///     fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox
+    ///     fn method4(self: Rc<&'a T>); // ExplicitSelf::Other
+    ///
+    ///     // Invalid cases will be caught by `check_method_receiver`:
+    ///     fn method_err1(self: &'a mut T); // ExplicitSelf::Other
+    ///     fn method_err2(self: &'static T) // ExplicitSelf::ByValue
+    ///     fn method_err3(self: &&T) // ExplicitSelf::ByReference
+    /// }
+    /// ```
+    ///
+    pub fn determine<P>(
+        self_arg_ty: Ty<'tcx>,
+        is_self_ty: P
+    ) -> ExplicitSelf<'tcx>
+    where
+        P: Fn(Ty<'tcx>) -> bool
+    {
+        use self::ExplicitSelf::*;
+
+        match self_arg_ty.sty {
+            _ if is_self_ty(self_arg_ty) => ByValue,
+            ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if is_self_ty(ty) => {
+                ByReference(region, mutbl)
+            }
+            ty::TyAdt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
+            _ => Other
+        }
+    }
+}
+
 pub fn provide(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         is_copy_raw,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0bcdcd3691e..95b19616e5e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1386,64 +1386,3 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
         vec
     }
 }
-
-pub enum ExplicitSelf<'tcx> {
-    ByValue,
-    ByReference(ty::Region<'tcx>, hir::Mutability),
-    ByBox
-}
-
-impl<'tcx> ExplicitSelf<'tcx> {
-    /// We wish to (for now) categorize an explicit self
-    /// declaration like `self: SomeType` into either `self`,
-    /// `&self`, `&mut self`, or `Box<self>`. We do this here
-    /// by some simple pattern matching. A more precise check
-    /// is done later in `check_method_receiver()`.
-    ///
-    /// Examples:
-    ///
-    /// ```
-    /// impl Foo for &T {
-    ///     // Legal declarations:
-    ///     fn method1(self: &&T); // ExplicitSelf::ByReference
-    ///     fn method2(self: &T); // ExplicitSelf::ByValue
-    ///     fn method3(self: Box<&T>); // ExplicitSelf::ByBox
-    ///
-    ///     // Invalid cases will be caught later by `check_method_receiver`:
-    ///     fn method_err1(self: &mut T); // ExplicitSelf::ByReference
-    /// }
-    /// ```
-    ///
-    /// To do the check we just count the number of "modifiers"
-    /// on each type and compare them. If they are the same or
-    /// the impl has more, we call it "by value". Otherwise, we
-    /// look at the outermost modifier on the method decl and
-    /// call it by-ref, by-box as appropriate. For method1, for
-    /// example, the impl type has one modifier, but the method
-    /// type has two, so we end up with
-    /// ExplicitSelf::ByReference.
-    pub fn determine(untransformed_self_ty: Ty<'tcx>,
-                     self_arg_ty: Ty<'tcx>)
-                     -> ExplicitSelf<'tcx> {
-        fn count_modifiers(ty: Ty) -> usize {
-            match ty.sty {
-                ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
-                ty::TyAdt(def, _) if def.is_box() => count_modifiers(ty.boxed_ty()) + 1,
-                _ => 0,
-            }
-        }
-
-        let impl_modifiers = count_modifiers(untransformed_self_ty);
-        let method_modifiers = count_modifiers(self_arg_ty);
-
-        if impl_modifiers >= method_modifiers {
-            ExplicitSelf::ByValue
-        } else {
-            match self_arg_ty.sty {
-                ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl),
-                ty::TyAdt(def, _) if def.is_box() => ExplicitSelf::ByBox,
-                _ => ExplicitSelf::ByValue,
-            }
-        }
-    }
-}
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 554a858bcc1..2c44c40d83d 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -13,6 +13,7 @@ use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
 use rustc::middle::region;
 use rustc::ty::{self, TyCtxt};
+use rustc::ty::util::ExplicitSelf;
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
@@ -21,7 +22,6 @@ use rustc::util::common::ErrorReported;
 use syntax_pos::Span;
 
 use super::{Inherited, FnCtxt};
-use astconv::ExplicitSelf;
 
 /// Checks that a method from an impl conforms to the signature of
 /// the same method as declared in the trait.
@@ -503,12 +503,17 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             ty::TraitContainer(_) => tcx.mk_self_type()
         };
         let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
-        match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) {
-            ExplicitSelf::ByValue => "self".to_string(),
-            ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
-            ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(),
-            _ => format!("self: {}", self_arg_ty)
-        }
+        let param_env = ty::ParamEnv::empty(Reveal::All);
+
+        tcx.infer_ctxt().enter(|infcx| {
+            let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
+            match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
+                ExplicitSelf::ByValue => "self".to_string(),
+                ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
+                ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(),
+                _ => format!("self: {}", self_arg_ty)
+            }
+        })
     };
 
     match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 483af08cabf..37cf67fe53e 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -8,19 +8,20 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use astconv::ExplicitSelf;
 use check::{Inherited, FnCtxt};
 use constrained_type_params::{identify_constrained_type_params, Parameter};
 
 use hir::def_id::DefId;
 use rustc::traits::{self, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::util::ExplicitSelf;
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::middle::lang_items;
 
 use syntax::ast;
+use syntax::feature_gate::{self, GateIssue};
 use syntax_pos::Span;
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder, DiagnosticId};
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir;
@@ -451,8 +452,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                          method: &ty::AssociatedItem,
                                          self_ty: Ty<'tcx>)
     {
-        // check that the type of the method's receiver matches the
-        // method's first parameter.
+        // check that the method has a valid receiver type, given the type `Self`
         debug!("check_method_receiver({:?}, self_ty={:?})",
                method, self_ty);
 
@@ -468,26 +468,57 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
 
         debug!("check_method_receiver: sig={:?}", sig);
 
+        let self_ty = fcx.normalize_associated_types_in(span, &self_ty);
+        let self_ty = fcx.liberate_late_bound_regions(
+            method.def_id,
+            &ty::Binder(self_ty)
+        );
+
         let self_arg_ty = sig.inputs()[0];
-        let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
-            ExplicitSelf::ByValue => self_ty,
-            ExplicitSelf::ByReference(region, mutbl) => {
-                fcx.tcx.mk_ref(region, ty::TypeAndMut {
-                    ty: self_ty,
-                    mutbl,
-                })
+
+        let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
+        let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
+        let self_arg_ty = fcx.liberate_late_bound_regions(
+            method.def_id,
+            &ty::Binder(self_arg_ty)
+        );
+
+        let mut autoderef = fcx.autoderef(span, self_arg_ty);
+
+        loop {
+            if let Some((potential_self_ty, _)) = autoderef.next() {
+                debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
+                    potential_self_ty, self_ty);
+
+                if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
+                    autoderef.finalize();
+                    if let Some(mut err) = fcx.demand_eqtype_with_origin(
+                        &cause, self_ty, potential_self_ty) {
+                        err.emit();
+                    }
+                    break
+                }
+            } else {
+                fcx.tcx.sess.diagnostic().mut_span_err(
+                    span, &format!("invalid `self` type: {:?}", self_arg_ty))
+                .note(&format!("type must be `{:?}` or a type that dereferences to it`", self_ty))
+                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .code(DiagnosticId::Error("E0307".into()))
+                .emit();
+                return
             }
-            ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty)
-        };
-        let rcvr_ty = fcx.normalize_associated_types_in(span, &rcvr_ty);
-        let rcvr_ty = fcx.liberate_late_bound_regions(method.def_id,
-                                                      &ty::Binder(rcvr_ty));
+        }
 
-        debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
+        let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
+        let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
 
-        let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
-        if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) {
-            err.emit();
+        if let ExplicitSelf::Other = self_kind {
+            if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
+                feature_gate::feature_err(&fcx.tcx.sess.parse_sess, "arbitrary_self_types", span,
+                    GateIssue::Language, "arbitrary `self` types are unstable")
+                .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
+                .emit();
+            }
         }
     }
 
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 0c3a88a8e9a..73bec697d49 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4724,6 +4724,7 @@ register_diagnostics! {
 //  E0247,
 //  E0248, // value used as a type, now reported earlier during resolution as E0412
 //  E0249,
+    E0307, // invalid method `self` type
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
 //  E0372, // coherence not object safe
     E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index a69bf53ee14..b6cb3ac1308 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -409,6 +409,9 @@ declare_features! (
 
     // extern types
     (active, extern_types, "1.23.0", Some(43467)),
+
+    // Allow trait methods with arbitrary self types
+    (active, arbitrary_self_types, "1.23.0", Some(44874)),
 );
 
 declare_features! (
diff --git a/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs
new file mode 100644
index 00000000000..6b10739bd8e
--- /dev/null
+++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs
@@ -0,0 +1,55 @@
+// Copyright 2017 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.
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+trait Foo {
+    fn foo(self: Rc<Self>) -> usize;
+}
+
+trait Bar {
+    fn foo(self: Rc<Self>) -> usize where Self: Sized;
+    fn bar(self: Box<Self>) -> usize;
+}
+
+impl Foo for usize {
+    fn foo(self: Rc<Self>) -> usize {
+        *self
+    }
+}
+
+impl Bar for usize {
+    fn foo(self: Rc<Self>) -> usize {
+        *self
+    }
+
+    fn bar(self: Box<Self>) -> usize {
+        *self
+    }
+}
+
+fn make_foo() {
+    let x = Box::new(5usize) as Box<Foo>;
+    //~^ ERROR E0038
+    //~| NOTE method `foo` has a non-standard `self` type
+    //~| NOTE the trait `Foo` cannot be made into an object
+    //~| ERROR E0038
+    //~| NOTE method `foo` has a non-standard `self` type
+    //~| NOTE the trait `Foo` cannot be made into an object
+    //~| NOTE requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<Foo>>`
+}
+
+fn make_bar() {
+    let x = Box::new(5usize) as Box<Bar>;
+    x.bar();
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-arbitrary-self-types.rs b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs
new file mode 100644
index 00000000000..ff0306f1993
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 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.
+
+use std::rc::Rc;
+
+trait Foo {
+    fn foo(self: Rc<Box<Self>>); //~ ERROR arbitrary `self` types are unstable
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(self: Rc<Box<Self>>) {} //~ ERROR arbitrary `self` types are unstable
+}
+
+impl Bar {
+    fn bar(self: Box<Rc<Self>>) {} //~ ERROR arbitrary `self` types are unstable
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs
index 664d62e87ae..1d5ef4360dc 100644
--- a/src/test/compile-fail/issue-17740.rs
+++ b/src/test/compile-fail/issue-17740.rs
@@ -15,12 +15,12 @@ struct Foo<'a> {
 impl <'a> Foo<'a>{
     fn bar(self: &mut Foo) {
     //~^ mismatched method receiver
-    //~| expected type `&mut Foo<'a>`
-    //~| found type `&mut Foo<'_>`
+    //~| expected type `Foo<'a>`
+    //~| found type `Foo<'_>`
     //~| lifetime mismatch
     //~| mismatched method receiver
-    //~| expected type `&mut Foo<'a>`
-    //~| found type `&mut Foo<'_>`
+    //~| expected type `Foo<'a>`
+    //~| found type `Foo<'_>`
     //~| lifetime mismatch
     }
 }
diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs
index ef91188c5d1..7ddd56229ce 100644
--- a/src/test/compile-fail/issue-26194.rs
+++ b/src/test/compile-fail/issue-26194.rs
@@ -12,7 +12,7 @@ struct S(String);
 
 impl S {
     fn f(self: *mut S) -> String { self.0 }
-    //~^ ERROR mismatched method receiver
+    //~^ ERROR invalid `self` type
 }
 
 fn main() { S("".to_owned()).f(); }
diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs
index a98b7cd4309..a0d1f2dc331 100644
--- a/src/test/compile-fail/ufcs-explicit-self-bad.rs
+++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs
@@ -15,7 +15,8 @@ struct Foo {
 }
 
 impl Foo {
-    fn foo(self: isize, x: isize) -> isize {  //~ ERROR mismatched method receiver
+    fn foo(self: isize, x: isize) -> isize {
+        //~^ ERROR invalid `self` type
         self.f + x
     }
 }
@@ -25,10 +26,12 @@ struct Bar<T> {
 }
 
 impl<T> Bar<T> {
-    fn foo(self: Bar<isize>, x: isize) -> isize { //~ ERROR mismatched method receiver
+    fn foo(self: Bar<isize>, x: isize) -> isize {
+        //~^ ERROR invalid `self` type
         x
     }
-    fn bar(self: &Bar<usize>, x: isize) -> isize {   //~ ERROR mismatched method receiver
+    fn bar(self: &Bar<usize>, x: isize) -> isize {
+        //~^ ERROR invalid `self` type
         x
     }
 }
@@ -45,12 +48,12 @@ impl<'a, T> SomeTrait for &'a Bar<T> {
     //~^ ERROR mismatched method receiver
     fn dummy3(self: &&Bar<T>) {}
     //~^ ERROR mismatched method receiver
-    //~| expected type `&&'a Bar<T>`
-    //~| found type `&&Bar<T>`
+    //~| expected type `&'a Bar<T>`
+    //~| found type `&Bar<T>`
     //~| lifetime mismatch
     //~| ERROR mismatched method receiver
-    //~| expected type `&&'a Bar<T>`
-    //~| found type `&&Bar<T>`
+    //~| expected type `&'a Bar<T>`
+    //~| found type `&Bar<T>`
     //~| lifetime mismatch
 }
 
diff --git a/src/test/compile-fail/E0308-2.rs b/src/test/run-pass/arbitrary_self_types_silly.rs
index 8c9fc955156..755a8d7ea29 100644
--- a/src/test/compile-fail/E0308-2.rs
+++ b/src/test/run-pass/arbitrary_self_types_silly.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -7,14 +7,23 @@
 // <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.
-
-use std::rc::Rc;
+#![feature(arbitrary_self_types)]
 
 struct Foo;
+struct Bar;
+
+impl std::ops::Deref for Bar {
+    type Target = Foo;
+
+    fn deref(&self) -> &Foo {
+        &Foo
+    }
+}
 
 impl Foo {
-    fn x(self: Rc<Foo>) {} //~ ERROR E0308
+    fn bar(self: Bar) -> i32 { 3 }
 }
 
 fn main() {
+    assert_eq!(3, Bar.bar());
 }
diff --git a/src/test/run-pass/arbitrary_self_types_struct.rs b/src/test/run-pass/arbitrary_self_types_struct.rs
new file mode 100644
index 00000000000..961717de046
--- /dev/null
+++ b/src/test/run-pass/arbitrary_self_types_struct.rs
@@ -0,0 +1,33 @@
+// Copyright 2017 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.
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+struct Foo {
+    x: i32,
+    y: i32,
+}
+
+impl Foo {
+    fn x(self: &Rc<Self>) -> i32 {
+        self.x
+    }
+
+    fn y(self: Rc<Self>) -> i32 {
+        self.y
+    }
+}
+
+fn main() {
+    let foo = Rc::new(Foo {x: 3, y: 4});
+    assert_eq!(3, foo.x());
+    assert_eq!(4, foo.y());
+}
diff --git a/src/test/run-pass/arbitrary_self_types_trait.rs b/src/test/run-pass/arbitrary_self_types_trait.rs
new file mode 100644
index 00000000000..e74d614dd6b
--- /dev/null
+++ b/src/test/run-pass/arbitrary_self_types_trait.rs
@@ -0,0 +1,28 @@
+// Copyright 2017 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.
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+trait Trait {
+    fn trait_method<'a>(self: &'a Box<Rc<Self>>) -> &'a [i32];
+}
+
+impl Trait for Vec<i32> {
+    fn trait_method<'a>(self: &'a Box<Rc<Self>>) -> &'a [i32] {
+        &***self
+    }
+}
+
+fn main() {
+    let v = vec![1,2,3];
+
+    assert_eq!(&[1,2,3], Box::new(Rc::new(v)).trait_method());
+}
diff --git a/src/test/run-pass/arbitrary_self_types_unsized_struct.rs b/src/test/run-pass/arbitrary_self_types_unsized_struct.rs
new file mode 100644
index 00000000000..8dc40e7aab1
--- /dev/null
+++ b/src/test/run-pass/arbitrary_self_types_unsized_struct.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 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.
+#![feature(arbitrary_self_types)]
+
+use std::rc::Rc;
+
+struct Foo<T: ?Sized>(T);
+
+impl Foo<[u8]> {
+    fn len(self: Rc<Self>) -> usize {
+        self.0.len()
+    }
+}
+
+fn main() {
+    let rc = Rc::new(Foo([1u8,2,3])) as Rc<Foo<[u8]>>;
+    assert_eq!(3, rc.len());
+}
diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr
index 117b109780b..e12fb57f15d 100644
--- a/src/test/ui/span/issue-27522.stderr
+++ b/src/test/ui/span/issue-27522.stderr
@@ -1,11 +1,11 @@
-error[E0308]: mismatched method receiver
+error[E0307]: invalid `self` type: &SomeType
   --> $DIR/issue-27522.rs:16:22
    |
 16 |     fn handler(self: &SomeType);
-   |                      ^^^^^^^^^ expected Self, found struct `SomeType`
+   |                      ^^^^^^^^^
    |
-   = note: expected type `&Self`
-              found type `&SomeType`
+   = note: type must be `Self` or a type that dereferences to it`
+   = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/static-lifetime.stderr b/src/test/ui/static-lifetime.stderr
index f73dff4f73d..adeabd91302 100644
--- a/src/test/ui/static-lifetime.stderr
+++ b/src/test/ui/static-lifetime.stderr
@@ -1,10 +1,15 @@
-error[E0477]: the type `std::borrow::Cow<'a, A>` does not fulfill the required lifetime
+error[E0478]: lifetime bound not satisfied
   --> $DIR/static-lifetime.rs:13:20
    |
 13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
    |                    ^^^^^^^^^
    |
-   = note: type must satisfy the static lifetime
+note: lifetime parameter instantiated with the lifetime 'a as defined on the impl at 13:1
+  --> $DIR/static-lifetime.rs:13:1
+   |
+13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: but lifetime parameter must outlive the static lifetime
 
 error: aborting due to previous error