about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/wfcheck.rs23
-rw-r--r--src/librustc_typeck/diagnostics.rs1
-rw-r--r--src/libsyntax/feature_gate.rs3
3 files changed, 27 insertions, 0 deletions
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 483af08cabf..9f3fd33260e 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -469,6 +469,29 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
         debug!("check_method_receiver: sig={:?}", sig);
 
         let self_arg_ty = sig.inputs()[0];
+
+        if fcx.tcx.sess.features.borrow().arbitrary_self_types {
+            let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
+
+            let mut autoderef = fcx.autoderef(span, self_arg_ty);
+            while let Some((potential_self_ty, _)) = autoderef.next() {
+                debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty);
+
+                // there's gotta be a more idiomatic way of checking if types are equal than this
+                if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) {
+                    err.cancel();
+                    continue;
+                } else {
+                    // we found a type that matches `self_ty`
+                    autoderef.finalize();
+                    return;
+                }
+            }
+
+            span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty);
+            return;
+        }
+
         let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
             ExplicitSelf::ByValue => self_ty,
             ExplicitSelf::ByReference(region, mutbl) => {
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 075367cbbb7..5581613afd8 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! (