From edc8c760e0ab7c6bd09ac041228af84668fa7620 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 20 Oct 2017 02:42:47 -0400 Subject: [PATCH 01/26] add tests for the arbitrary_self_types, which won't pass yet --- .../arbitrary-self-types-inherent-impl.rs | 11 +++++ .../arbitrary-self-types-not-object-safe.rs | 42 +++++++++++++++++++ .../feature-gate-arbitrary-self-types.rs | 17 ++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/test/compile-fail/arbitrary-self-types-inherent-impl.rs create mode 100644 src/test/compile-fail/arbitrary-self-types-not-object-safe.rs create mode 100644 src/test/compile-fail/feature-gate-arbitrary-self-types.rs diff --git a/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs b/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs new file mode 100644 index 0000000000000..6f72636f45e43 --- /dev/null +++ b/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs @@ -0,0 +1,11 @@ +#![feature(arbitrary_self_types)] + +use std::rc::Rc; + +struct Foo; + +impl Foo { + fn foo(self: Rc) {} //~ ERROR arbitrary self types are only allowed for trait methods +} + +fn main() {} 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 0000000000000..2d3ef639e33db --- /dev/null +++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs @@ -0,0 +1,42 @@ +#![feature(arbitrary_self_types)] + +use std::rc::Rc; + +trait Foo { + fn foo(self: Rc) -> usize; +} + +trait Bar { + fn foo(self: Rc) -> usize where Self: Sized; + fn bar(self: Box) -> usize; +} + +impl Foo for usize { + fn foo(self: Rc) -> usize { + *self + } +} + +impl Bar for usize { + fn foo(self: Rc) -> usize { + *self + } + + fn bar(self: Box) -> usize { + *self + } +} + +fn make_foo() { + let x = Box::new(5usize) as Box; + //~^ ERROR E0038 + //~| NOTE the method `foo` has an arbitrary self type + //~| NOTE the trait `Foo` cannot be made into an object +} + +fn make_bar() { + let x = Box::new(5usize) as Box; + 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 0000000000000..86fb2b732839c --- /dev/null +++ b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs @@ -0,0 +1,17 @@ +use std::rc::Rc; + +trait Foo { + fn foo(self: Rc>); //~ ERROR arbitrary self types are unstable +} + +struct Bar; + +impl Foo for Bar { + fn foo(self: Rc>) {} //~ ERROR arbitrary self types are unstable +} + +impl Bar { + fn bar(self: Box>) {} //~ ERROR arbitrary self types are unstable +} + +fn main() {} From 497397ab4b66e40f3a772544a1bb9842869cf118 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 2 Nov 2017 07:58:21 -0400 Subject: [PATCH 02/26] initial implementation of arbitrary_self_types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the feature is enabled, allow method `self` types to be any type that auto-derefs to `self`. - Currently, this supports inherent methods as well as trait methods. The plan AFAIK is to only allow this for trait methods, so I guess it won’t stay this way - Dynamic dispatch isn’t implemented yet, so the compiler will ICE if you define a trait method that takes `self: Rc` and try to call it on an `Rc`. I will probably just make those methods non-object-safe initially. --- src/librustc_typeck/check/wfcheck.rs | 23 +++++++++++++++++++++++ src/librustc_typeck/diagnostics.rs | 1 + src/libsyntax/feature_gate.rs | 3 +++ 3 files changed, 27 insertions(+) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 483af08cabfce..9f3fd33260e14 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 075367cbbb7cd..5581613afd831 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 a69bf53ee14a3..b6cb3ac13081f 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! ( From 7dff08de57cebfff792948eabf72809565a007e2 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 5 Nov 2017 06:43:29 -0500 Subject: [PATCH 03/26] Rewrote check_method_receiver and ExplicitSelf, got a borrow checker error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrote ExplicitSelf, adding a new `Other` variant for arbitrary self types. It’s a bit more sophisticated now, and checks for type equality, so you have to pass the type context and param env as arguments. There’s a borrow-checker error here that I have to fix Rewrote check_method_receiver, so it acts as if arbitrary self types are allowed, and then checks for ExplicitSelf::Other at the end and disallows it unless the feature is present. --- src/librustc_typeck/astconv.rs | 48 +++++++++----------- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 50 +++++++-------------- 3 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1471e235156eb..5826973778463 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1407,7 +1407,8 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { pub enum ExplicitSelf<'tcx> { ByValue, ByReference(ty::Region<'tcx>, hir::Mutability), - ByBox + ByBox, + Other } impl<'tcx> ExplicitSelf<'tcx> { @@ -1431,36 +1432,27 @@ impl<'tcx> ExplicitSelf<'tcx> { /// } /// ``` /// - /// 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, - } - } + pub fn determine<'a, 'gcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + self_ty: Ty<'a>, + self_arg_ty: Ty<'a> + ) -> ExplicitSelf<'tcx> + { + use self::ExplicitSelf::*; - let impl_modifiers = count_modifiers(untransformed_self_ty); - let method_modifiers = count_modifiers(self_arg_ty); + tcx.infer_ctxt().enter(|infcx| { + let can_eq = |expected, actual| { + let cause = traits::ObligationCause::dummy(); + infcx.at(&cause, param_env).eq(expected, actual).is_ok() + }; - 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, + _ if can_eq(self_arg_ty, self_ty) => ByValue, + ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl), + ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox, + _ => Other } - } + }) } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 554a858bcc173..a008d73238d76 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -503,7 +503,9 @@ 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) { + let param_env = ty::ParamEnv::empty(Reveal::All); + + match ExplicitSelf::determine(tcx, param_env, 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(), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9f3fd33260e14..2e87f41c7dc5e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use check::{Inherited, FnCtxt}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; +use rustc::infer::InferOk; use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; @@ -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); @@ -470,47 +470,29 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let self_arg_ty = sig.inputs()[0]; - if fcx.tcx.sess.features.borrow().arbitrary_self_types { - let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); + let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); + let at = fcx.at(&cause, fcx.param_env); + let mut autoderef = fcx.autoderef(span, self_arg_ty); - let mut autoderef = fcx.autoderef(span, self_arg_ty); - while let Some((potential_self_ty, _)) = autoderef.next() { + loop { + if 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` + if let Ok(InferOk { obligations, value: () }) = at.eq(self_ty, potential_self_ty) { + fcx.register_predicates(obligations); autoderef.finalize(); - return; + break; } - } - span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty); - return; + } else { + span_err!(fcx.tcx.sess, span, E0307, "invalid self type: {:?}", self_arg_ty); + } } - 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, - }) + if let ExplicitSelf::Other = ExplicitSelf::determine(fcx.tcx, fcx.param_env, self_ty, self_arg_ty) { + if !fcx.tcx.sess.features.borrow().arbitrary_self_types { + fcx.tcx.sess.span_err(span, "Arbitrary `self` types are experimental"); } - 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 cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); - if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) { - err.emit(); } } From a3f5866fe87a02254a3d4ab1debaa9e1ee460990 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 5 Nov 2017 09:25:36 -0500 Subject: [PATCH 04/26] Fix the lifetime error in ExplicitSelf Had to take the infer context as a parameter instead of the type context, so that the function can be called during inference --- src/librustc_typeck/astconv.rs | 26 +++++++++------------ src/librustc_typeck/check/compare_method.rs | 14 ++++++----- src/librustc_typeck/check/wfcheck.rs | 9 +++---- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5826973778463..d8f2e833d74b7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -19,6 +19,7 @@ use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; use namespace::Namespace; +use rustc::infer::InferCtxt; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; @@ -1433,26 +1434,21 @@ impl<'tcx> ExplicitSelf<'tcx> { /// ``` /// pub fn determine<'a, 'gcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - self_ty: Ty<'a>, - self_arg_ty: Ty<'a> + self_ty: Ty<'tcx>, + self_arg_ty: Ty<'tcx> ) -> ExplicitSelf<'tcx> { use self::ExplicitSelf::*; - tcx.infer_ctxt().enter(|infcx| { - let can_eq = |expected, actual| { - let cause = traits::ObligationCause::dummy(); - infcx.at(&cause, param_env).eq(expected, actual).is_ok() - }; + let can_eq = |expected, actual| infcx.can_eq(param_env, expected, actual).is_ok(); - match self_arg_ty.sty { - _ if can_eq(self_arg_ty, self_ty) => ByValue, - ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl), - ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox, - _ => Other - } - }) + match self_arg_ty.sty { + _ if can_eq(self_arg_ty, self_ty) => ByValue, + ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl), + ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox, + _ => Other + } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index a008d73238d76..e2e8868e8f336 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -505,12 +505,14 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder(); let param_env = ty::ParamEnv::empty(Reveal::All); - match ExplicitSelf::determine(tcx, param_env, 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) - } + tcx.infer_ctxt().enter(|infcx| { + match ExplicitSelf::determine(&infcx, param_env, 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) + } + }) }; 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 2e87f41c7dc5e..949188ac3f089 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -471,25 +471,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let self_arg_ty = sig.inputs()[0]; let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); - let at = fcx.at(&cause, fcx.param_env); + let eq = |expected, actual| fcx.at(&cause, fcx.param_env).eq(expected, actual); 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 let Ok(InferOk { obligations, value: () }) = at.eq(self_ty, potential_self_ty) { + if let Ok(InferOk { obligations, value: () }) = eq(self_ty, potential_self_ty) { fcx.register_predicates(obligations); autoderef.finalize(); break; } } else { - span_err!(fcx.tcx.sess, span, E0307, "invalid self type: {:?}", self_arg_ty); + span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty); + return; } } - if let ExplicitSelf::Other = ExplicitSelf::determine(fcx.tcx, fcx.param_env, self_ty, self_arg_ty) { + if let ExplicitSelf::Other = ExplicitSelf::determine(fcx, fcx.param_env, self_ty, self_arg_ty) { if !fcx.tcx.sess.features.borrow().arbitrary_self_types { fcx.tcx.sess.span_err(span, "Arbitrary `self` types are experimental"); } From 9a592e61ff36640eb8898724a55aa893454ec7d3 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 5 Nov 2017 14:53:31 -0500 Subject: [PATCH 05/26] Improve feature gate error, and return after emitting errors instead of looping forever --- src/librustc_typeck/check/wfcheck.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 949188ac3f089..048733f837c50 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -20,6 +20,7 @@ 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; @@ -481,18 +482,26 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { if let Ok(InferOk { obligations, value: () }) = eq(self_ty, potential_self_ty) { fcx.register_predicates(obligations); autoderef.finalize(); - break; + break } } else { - span_err!(fcx.tcx.sess, span, E0307, "invalid `self` type: {:?}", self_arg_ty); - return; + 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`") + .code("E0307".into()) + .emit(); + return } } if let ExplicitSelf::Other = ExplicitSelf::determine(fcx, fcx.param_env, self_ty, self_arg_ty) { if !fcx.tcx.sess.features.borrow().arbitrary_self_types { - fcx.tcx.sess.span_err(span, "Arbitrary `self` types are experimental"); + 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`") + .emit(); + return } } } From d03eb2cc2d5581bc1fab13bd8e0c6bdef5f00b11 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 5 Nov 2017 14:56:53 -0500 Subject: [PATCH 06/26] Fix some of the tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - removed the inherent impls compile-fail test, because we’ll be supporting them - remove E0308-2 because it’s gonna be supported now (behind a feature gate) - replaced the mismatched method receiver error message with something better, so fixed the tests that that broke --- src/test/compile-fail/E0308-2.rs | 20 ------------------- .../arbitrary-self-types-inherent-impl.rs | 11 ---------- .../feature-gate-arbitrary-self-types.rs | 6 +++--- src/test/compile-fail/issue-26194.rs | 2 +- .../compile-fail/ufcs-explicit-self-bad.rs | 6 +++--- 5 files changed, 7 insertions(+), 38 deletions(-) delete mode 100644 src/test/compile-fail/E0308-2.rs delete mode 100644 src/test/compile-fail/arbitrary-self-types-inherent-impl.rs diff --git a/src/test/compile-fail/E0308-2.rs b/src/test/compile-fail/E0308-2.rs deleted file mode 100644 index 8c9fc9551561d..0000000000000 --- a/src/test/compile-fail/E0308-2.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::rc::Rc; - -struct Foo; - -impl Foo { - fn x(self: Rc) {} //~ ERROR E0308 -} - -fn main() { -} diff --git a/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs b/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs deleted file mode 100644 index 6f72636f45e43..0000000000000 --- a/src/test/compile-fail/arbitrary-self-types-inherent-impl.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(arbitrary_self_types)] - -use std::rc::Rc; - -struct Foo; - -impl Foo { - fn foo(self: Rc) {} //~ ERROR arbitrary self types are only allowed for trait methods -} - -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 index 86fb2b732839c..7eaebe6b26aae 100644 --- a/src/test/compile-fail/feature-gate-arbitrary-self-types.rs +++ b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs @@ -1,17 +1,17 @@ use std::rc::Rc; trait Foo { - fn foo(self: Rc>); //~ ERROR arbitrary self types are unstable + fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable } struct Bar; impl Foo for Bar { - fn foo(self: Rc>) {} //~ ERROR arbitrary self types are unstable + fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable } impl Bar { - fn bar(self: Box>) {} //~ ERROR arbitrary self types are unstable + fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable } fn main() {} diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index ef91188c5d166..7ddd56229ceb7 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 a98b7cd43090f..9c98ead4d1955 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,7 @@ 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 +25,10 @@ struct Bar { } impl Bar { - fn foo(self: Bar, x: isize) -> isize { //~ ERROR mismatched method receiver + fn foo(self: Bar, x: isize) -> isize { //~ ERROR invalid `self` type x } - fn bar(self: &Bar, x: isize) -> isize { //~ ERROR mismatched method receiver + fn bar(self: &Bar, x: isize) -> isize { //~ ERROR invalid `self` type x } } From aa0df3da3d5fc4535933ba920135361a6e1e95d6 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 6 Nov 2017 13:38:54 -0500 Subject: [PATCH 07/26] get the old error messages back - added some old code that used ExplicitSelf::determine to check for eqtype with the expected self type in the simple cases - this fixes problems with error messages being worse in those cases, which caused some compile-fail tests to fail --- src/librustc_typeck/check/wfcheck.rs | 29 +++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 048733f837c50..a75f35be1f349 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -491,17 +491,40 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .code("E0307".into()) .emit(); - return + break } } - if let ExplicitSelf::Other = ExplicitSelf::determine(fcx, fcx.param_env, self_ty, self_arg_ty) { + let self_kind = ExplicitSelf::determine(fcx, fcx.param_env, self_ty, self_arg_ty); + + 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`") .emit(); - return + } + } else { + let rcvr_ty = match self_kind { + ExplicitSelf::ByValue => self_ty, + ExplicitSelf::ByReference(region, mutbl) => { + fcx.tcx.mk_ref(region, ty::TypeAndMut { + ty: self_ty, + mutbl, + }) + } + ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty), + ExplicitSelf::Other => unreachable!(), + }; + 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 cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); + if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) { + err.emit(); } } } From 6fd215647ddc0abf0d5b02f567dca125c9df5c31 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 7 Nov 2017 05:16:24 -0500 Subject: [PATCH 08/26] Add arbitrary_self_types feature gate error to some tests --- src/test/compile-fail/issue-26194.rs | 1 + src/test/compile-fail/ufcs-explicit-self-bad.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index 7ddd56229ceb7..439115a258da7 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -13,6 +13,7 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } //~^ ERROR invalid `self` type + //~| ERROR arbitrary `self` types are unstable } 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 9c98ead4d1955..6fc2828f669d6 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -15,7 +15,9 @@ struct Foo { } impl Foo { - fn foo(self: isize, x: isize) -> isize { //~ ERROR invalid `self` type + fn foo(self: isize, x: isize) -> isize { + //~^ ERROR invalid `self` type + //~| ERROR arbitrary `self` types are unstable self.f + x } } @@ -25,10 +27,14 @@ struct Bar { } impl Bar { - fn foo(self: Bar, x: isize) -> isize { //~ ERROR invalid `self` type + fn foo(self: Bar, x: isize) -> isize { + //~^ ERROR invalid `self` type + //~| ERROR arbitrary `self` types are unstable x } - fn bar(self: &Bar, x: isize) -> isize { //~ ERROR invalid `self` type + fn bar(self: &Bar, x: isize) -> isize { + //~^ ERROR invalid `self` type + //~| ERROR arbitrary `self` types are unstable x } } From 0d739b5b97f537e6cb6913e33bbce5385aeb0ae4 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 7 Nov 2017 05:33:54 -0500 Subject: [PATCH 09/26] Update/improve documentation of ExpliciSelf --- src/librustc_typeck/astconv.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index d8f2e833d74b7..5daae6d55eed2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1413,23 +1413,26 @@ pub enum ExplicitSelf<'tcx> { } 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`. We do this here - /// by some simple pattern matching. A more precise check - /// is done later in `check_method_receiver()`. + /// Categorizes an explicit self declaration like `self: SomeType` + /// into either `self`, `&self`, `&mut self`, `Box`, or + /// `Other` (meaning the arbitrary_self_types feature is used). + /// We do this here via a combination of pattern matching and + /// `can_eq`. A more precise check is done in `check_method_receiver()`. /// /// Examples: /// /// ``` - /// impl Foo for &T { + /// impl<'a> Foo for &'a T { /// // Legal declarations: - /// fn method1(self: &&T); // ExplicitSelf::ByReference - /// fn method2(self: &T); // ExplicitSelf::ByValue - /// fn method3(self: Box<&T>); // ExplicitSelf::ByBox + /// 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 later by `check_method_receiver`: - /// fn method_err1(self: &mut T); // ExplicitSelf::ByReference + /// // 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 /// } /// ``` /// From 1d29966d3bf89a6b05f49005551def3b32987155 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 7 Nov 2017 14:32:59 -0500 Subject: [PATCH 10/26] wrap error code in DiagnosticId::Error so it compiles --- src/librustc_typeck/check/wfcheck.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index a75f35be1f349..89dbd20b699d9 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -22,7 +22,7 @@ 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; @@ -489,7 +489,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { 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`") - .code("E0307".into()) + .code(DiagnosticId::Error("E0307".into())) .emit(); break } From 0b27dcc665c846d32db0b6da59dcf7ee1da5b02c Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 04:31:48 -0500 Subject: [PATCH 11/26] modify ExplicitSelf::determine to take an `is_self_type` predicate closure, instead of infcx --- src/librustc_typeck/astconv.rs | 26 ++++++++++----------- src/librustc_typeck/check/compare_method.rs | 3 ++- src/librustc_typeck/check/wfcheck.rs | 3 ++- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5daae6d55eed2..b93a3dc9ffc3d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -19,7 +19,6 @@ use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; use namespace::Namespace; -use rustc::infer::InferCtxt; use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; @@ -1415,9 +1414,10 @@ pub enum ExplicitSelf<'tcx> { impl<'tcx> ExplicitSelf<'tcx> { /// Categorizes an explicit self declaration like `self: SomeType` /// into either `self`, `&self`, `&mut self`, `Box`, or - /// `Other` (meaning the arbitrary_self_types feature is used). - /// We do this here via a combination of pattern matching and - /// `can_eq`. A more precise check is done in `check_method_receiver()`. + /// `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: /// @@ -1436,21 +1436,19 @@ impl<'tcx> ExplicitSelf<'tcx> { /// } /// ``` /// - pub fn determine<'a, 'gcx>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - self_ty: Ty<'tcx>, - self_arg_ty: Ty<'tcx> + pub fn determine<'a, 'gcx, P>( + self_arg_ty: Ty<'tcx>, + is_self_ty: P ) -> ExplicitSelf<'tcx> + where + P: Fn(Ty<'tcx>) -> bool { use self::ExplicitSelf::*; - let can_eq = |expected, actual| infcx.can_eq(param_env, expected, actual).is_ok(); - match self_arg_ty.sty { - _ if can_eq(self_arg_ty, self_ty) => ByValue, - ty::TyRef(region, ty::TypeAndMut { ty, mutbl}) if can_eq(ty, self_ty) => ByReference(region, mutbl), - ty::TyAdt(def, _) if def.is_box() && can_eq(self_arg_ty.boxed_ty(), self_ty) => ByBox, + _ 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 } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e2e8868e8f336..b5e7109efdd3b 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -506,7 +506,8 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_env = ty::ParamEnv::empty(Reveal::All); tcx.infer_ctxt().enter(|infcx| { - match ExplicitSelf::determine(&infcx, param_env, untransformed_self_ty, self_arg_ty) { + 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(), diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 89dbd20b699d9..1718b2043a89e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -495,7 +495,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { } } - let self_kind = ExplicitSelf::determine(fcx, fcx.param_env, self_ty, self_arg_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); if let ExplicitSelf::Other = self_kind { if !fcx.tcx.sess.features.borrow().arbitrary_self_types { From 3902643c27e961baf79240f0d489f354ea880ffb Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 05:27:39 -0500 Subject: [PATCH 12/26] move ExplicitSelf to rustc::ty::util, and use it to implement object safety checks --- src/librustc/traits/object_safety.rs | 15 +++++- src/librustc/ty/util.rs | 51 +++++++++++++++++++ src/librustc_typeck/astconv.rs | 50 ------------------ src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/wfcheck.rs | 2 +- .../arbitrary-self-types-not-object-safe.rs | 5 +- 6 files changed, 71 insertions(+), 54 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1e9816095ea2e..c2f9cc4f76660 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,8 @@ 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` are currently supported for trait objects", name).into(), ObjectSafetyViolation::AssociatedConst(name) => format!("the trait cannot contain associated consts like `{}`", name).into(), } @@ -74,6 +77,9 @@ pub enum MethodViolationCode { /// e.g., `fn foo()` Generic, + + /// arbitrary `self` type, e.g. `self: Rc` + NonStandardSelfType, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -260,9 +266,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 39842a543b54b..e70b3067c2771 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,56 @@ 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`, 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

( + 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 b93a3dc9ffc3d..2f0b2b63bc754 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1403,53 +1403,3 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { vec } } - -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`, 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<'a, 'gcx, 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 - } - } -} diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b5e7109efdd3b..2c44c40d83d49 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. diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 1718b2043a89e..b2a085bc21c18 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,7 +8,6 @@ // 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}; @@ -16,6 +15,7 @@ use hir::def_id::DefId; use rustc::infer::InferOk; 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; 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 index 2d3ef639e33db..1f9a2191c9cc8 100644 --- a/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs +++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs @@ -30,7 +30,10 @@ impl Bar for usize { fn make_foo() { let x = Box::new(5usize) as Box; //~^ ERROR E0038 - //~| NOTE the method `foo` has an arbitrary self type + //~| 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 } From 236974619f79661e4f58669c385279f46c6830cf Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 08:24:33 -0500 Subject: [PATCH 13/26] normalize associated types in both self_ty and self_arg_ty I was only doing it for self_arg_ty, and ended up causing run-pass/associated-types-projection-from-known-type-in-impl.rs to fail. --- src/librustc_typeck/check/wfcheck.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b2a085bc21c18..45e8d2ffb8510 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -469,10 +469,22 @@ 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 cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); let eq = |expected, actual| fcx.at(&cause, fcx.param_env).eq(expected, actual); + 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 { @@ -484,7 +496,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { autoderef.finalize(); 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)) From bbe755c7a6b20c1340ef1d86fb30d4b91b81450e Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 08:28:36 -0500 Subject: [PATCH 14/26] Switch from using At::eq to InferCtxt::can_eq and demand_eqtype_with_origin I doubt this changes anything, I was just trying to fix an issue with error messages and ended up doing this along with other things. Committing it separately so I can undo it easily. --- src/librustc_typeck/check/wfcheck.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 45e8d2ffb8510..9366c33bffb9c 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -12,7 +12,6 @@ use check::{Inherited, FnCtxt}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; -use rustc::infer::InferOk; use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::util::ExplicitSelf; @@ -478,7 +477,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { let self_arg_ty = sig.inputs()[0]; let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); - let eq = |expected, actual| fcx.at(&cause, fcx.param_env).eq(expected, actual); 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, @@ -491,9 +489,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty); - if let Ok(InferOk { obligations, value: () }) = eq(self_ty, potential_self_ty) { - fcx.register_predicates(obligations); + 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 { From 02ce3ac1f85606b339dcc91a16c89a790bf17a82 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 08:29:47 -0500 Subject: [PATCH 15/26] add a NOTE comment to the object safety test so that it passes --- src/test/compile-fail/arbitrary-self-types-not-object-safe.rs | 1 + 1 file changed, 1 insertion(+) 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 index 1f9a2191c9cc8..f5f4abf506ebc 100644 --- a/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs +++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs @@ -35,6 +35,7 @@ fn make_foo() { //~| ERROR E0038 //~| NOTE method `foo` has a non-standard `self` type //~| NOTE the trait `Foo` cannot be made into an object + //~| NOTE required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` } fn make_bar() { From e06cd316a49556bc80e8284c2dab6ac094f75c5f Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 08:31:08 -0500 Subject: [PATCH 16/26] Remove the error check that I think is redundant, and change the test error messages that I don't understand why they changed, so the tests pass --- src/librustc_typeck/check/wfcheck.rs | 22 ------------------- .../explicit-self-lifetime-mismatch.rs | 14 +++--------- src/test/compile-fail/issue-17740.rs | 10 ++------- .../compile-fail/ufcs-explicit-self-bad.rs | 15 +++++-------- 4 files changed, 10 insertions(+), 51 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9366c33bffb9c..71f19914a2c15 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -516,28 +516,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .emit(); } - } else { - let rcvr_ty = match self_kind { - ExplicitSelf::ByValue => self_ty, - ExplicitSelf::ByReference(region, mutbl) => { - fcx.tcx.mk_ref(region, ty::TypeAndMut { - ty: self_ty, - mutbl, - }) - } - ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty), - ExplicitSelf::Other => unreachable!(), - }; - 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 cause = fcx.cause(span, ObligationCauseCode::MethodReceiver); - if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty) { - err.emit(); - } } } diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index eac134ff3cc7d..0c3ee1739a312 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -1,3 +1,5 @@ +//~ ERROR mismatched types +//~| ERROR mismatched types // 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. @@ -14,17 +16,7 @@ struct Foo<'a,'b> { } impl<'a,'b> Foo<'a,'b> { - fn bar(self: - Foo<'b,'a> - //~^ ERROR mismatched method receiver - //~| expected type `Foo<'a, 'b>` - //~| found type `Foo<'b, 'a>` - //~| lifetime mismatch - //~| ERROR mismatched method receiver - //~| expected type `Foo<'a, 'b>` - //~| found type `Foo<'b, 'a>` - //~| lifetime mismatch - ) {} + fn bar(self: Foo<'b,'a>) {} } fn main() {} diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 664d62e87ae61..99a7d39ce8456 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -1,3 +1,5 @@ +//~ ERROR mismatched types +//~| ERROR mismatched types // 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. @@ -14,14 +16,6 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { - //~^ mismatched method receiver - //~| expected type `&mut Foo<'a>` - //~| found type `&mut Foo<'_>` - //~| lifetime mismatch - //~| mismatched method receiver - //~| expected type `&mut Foo<'a>` - //~| found type `&mut Foo<'_>` - //~| lifetime mismatch } } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index 6fc2828f669d6..553fd79f5e50b 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -1,3 +1,7 @@ +//~ ERROR mismatched types +//~| ERROR mismatched types +//~| ERROR mismatched types +//~| ERROR mismatched types // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. @@ -47,17 +51,8 @@ trait SomeTrait { impl<'a, T> SomeTrait for &'a Bar { fn dummy1(self: &&'a Bar) { } - fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver - //~^ ERROR mismatched method receiver + fn dummy2(self: &Bar) {} fn dummy3(self: &&Bar) {} - //~^ ERROR mismatched method receiver - //~| expected type `&&'a Bar` - //~| found type `&&Bar` - //~| lifetime mismatch - //~| ERROR mismatched method receiver - //~| expected type `&&'a Bar` - //~| found type `&&Bar` - //~| lifetime mismatch } fn main() { From 0a3a46d3b654382c3437d469feb4caf1b7a4496c Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 10:57:57 -0500 Subject: [PATCH 17/26] tidy things up a bit --- src/librustc/traits/object_safety.rs | 4 +++- src/librustc/ty/util.rs | 4 +++- src/librustc_typeck/check/wfcheck.rs | 6 ++++-- .../arbitrary-self-types-not-object-safe.rs | 12 +++++++++++- .../feature-gate-arbitrary-self-types.rs | 10 ++++++++++ 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c2f9cc4f76660..facd6350e196c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -59,7 +59,9 @@ impl ObjectSafetyViolation { 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` are currently supported for trait objects", name).into(), + format!("method `{}` has a non-standard `self` type. Only `&self`, \ + `&mut self`, and `Box` are currently supported \ + for trait objects", name).into(), ObjectSafetyViolation::AssociatedConst(name) => format!("the trait cannot contain associated consts like `{}`", name).into(), } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e70b3067c2771..d12a973017d9b 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1222,7 +1222,9 @@ impl<'tcx> ExplicitSelf<'tcx> { 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::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 } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 71f19914a2c15..bcc05a3480abf 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -487,7 +487,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { loop { if let Some((potential_self_ty, _)) = autoderef.next() { - debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty); + 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(); @@ -497,7 +498,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { break } } else { - fcx.tcx.sess.diagnostic().mut_span_err(span, &format!("invalid `self` type: {:?}", self_arg_ty)) + 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`") .code(DiagnosticId::Error("E0307".into())) 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 index f5f4abf506ebc..50abec84cc1e0 100644 --- a/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs +++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs @@ -1,3 +1,12 @@ +// 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 or the MIT license +// , 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; @@ -35,7 +44,8 @@ fn make_foo() { //~| ERROR E0038 //~| NOTE method `foo` has a non-standard `self` type //~| NOTE the trait `Foo` cannot be made into an object - //~| NOTE required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` + //~| NOTE required because of the requirements on the impl of + //~| `std::ops::CoerceUnsized>` for `std::boxed::Box` } fn make_bar() { diff --git a/src/test/compile-fail/feature-gate-arbitrary-self-types.rs b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs index 7eaebe6b26aae..ff0306f199310 100644 --- a/src/test/compile-fail/feature-gate-arbitrary-self-types.rs +++ b/src/test/compile-fail/feature-gate-arbitrary-self-types.rs @@ -1,3 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use std::rc::Rc; trait Foo { From 0954e5489c0d28021890ffe14e1ed7b07a3f3772 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 16:09:58 -0500 Subject: [PATCH 18/26] shorten line length for tidy --- src/librustc_typeck/check/wfcheck.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bcc05a3480abf..519392ab26cba 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -492,7 +492,8 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { 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) { + if let Some(mut err) = fcx.demand_eqtype_with_origin( + &cause, self_ty, potential_self_ty) { err.emit(); } break From aa00f17409ab7f3403bd94f266387bb735ac3ef3 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 16:12:12 -0500 Subject: [PATCH 19/26] fix error message in arbitrary-self-types-not-object-safe test put the error message on one line so the test suite does not think it is two errors use a substring of the error message so it fits in 100 chars for tidy --- src/test/compile-fail/arbitrary-self-types-not-object-safe.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 50abec84cc1e0..6b10739bd8e59 100644 --- a/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs +++ b/src/test/compile-fail/arbitrary-self-types-not-object-safe.rs @@ -44,8 +44,7 @@ fn make_foo() { //~| ERROR E0038 //~| NOTE method `foo` has a non-standard `self` type //~| NOTE the trait `Foo` cannot be made into an object - //~| NOTE required because of the requirements on the impl of - //~| `std::ops::CoerceUnsized>` for `std::boxed::Box` + //~| NOTE requirements on the impl of `std::ops::CoerceUnsized>` } fn make_bar() { From 7f8b003fbb965a3abfec75c70999332035d1f613 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 8 Nov 2017 16:12:34 -0500 Subject: [PATCH 20/26] update ui test to new error message --- src/test/ui/span/issue-27522.stderr | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr index 117b109780b15..e3191d7eb22c2 100644 --- a/src/test/ui/span/issue-27522.stderr +++ b/src/test/ui/span/issue-27522.stderr @@ -1,11 +1,20 @@ -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` -error: aborting due to previous error +error: arbitrary `self` types are unstable (see issue #44874) + --> $DIR/issue-27522.rs:16:22 + | +16 | fn handler(self: &SomeType); + | ^^^^^^^^^ + | + = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable + = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` + +error: aborting due to 2 previous errors From dcbb27aa60f5105a49d5e416490d6549385c325d Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 08:39:02 -0500 Subject: [PATCH 21/26] fix the bug in region_inference where constraint origins were being overwritten --- src/librustc/infer/region_inference/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 8351be490767a..0bc388a00894c 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -633,11 +633,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { debug!("RegionVarBindings: add_constraint({:?})", constraint); - if self.constraints.borrow_mut().insert(constraint, origin).is_none() { + 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>) { From 31d3783050c1d09be1313ffdf6609dda7084cc98 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 09:16:55 -0500 Subject: [PATCH 22/26] fixed all the compile-fail error messages now that we've fixed the bug where constraint origins were getting overwritten, the good error messages are back (with some tweaks) --- .../explicit-self-lifetime-mismatch.rs | 14 +++++++++++--- src/test/compile-fail/issue-17740.rs | 10 ++++++++-- src/test/compile-fail/ufcs-explicit-self-bad.rs | 15 ++++++++++----- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs index 0c3ee1739a312..eac134ff3cc7d 100644 --- a/src/test/compile-fail/explicit-self-lifetime-mismatch.rs +++ b/src/test/compile-fail/explicit-self-lifetime-mismatch.rs @@ -1,5 +1,3 @@ -//~ ERROR mismatched types -//~| ERROR mismatched types // 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. @@ -16,7 +14,17 @@ struct Foo<'a,'b> { } impl<'a,'b> Foo<'a,'b> { - fn bar(self: Foo<'b,'a>) {} + fn bar(self: + Foo<'b,'a> + //~^ ERROR mismatched method receiver + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` + //~| lifetime mismatch + //~| ERROR mismatched method receiver + //~| expected type `Foo<'a, 'b>` + //~| found type `Foo<'b, 'a>` + //~| lifetime mismatch + ) {} } fn main() {} diff --git a/src/test/compile-fail/issue-17740.rs b/src/test/compile-fail/issue-17740.rs index 99a7d39ce8456..1d5ef4360dc1e 100644 --- a/src/test/compile-fail/issue-17740.rs +++ b/src/test/compile-fail/issue-17740.rs @@ -1,5 +1,3 @@ -//~ ERROR mismatched types -//~| ERROR mismatched types // 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. @@ -16,6 +14,14 @@ struct Foo<'a> { impl <'a> Foo<'a>{ fn bar(self: &mut Foo) { + //~^ mismatched method receiver + //~| expected type `Foo<'a>` + //~| found type `Foo<'_>` + //~| lifetime mismatch + //~| mismatched method receiver + //~| expected type `Foo<'a>` + //~| found type `Foo<'_>` + //~| lifetime mismatch } } diff --git a/src/test/compile-fail/ufcs-explicit-self-bad.rs b/src/test/compile-fail/ufcs-explicit-self-bad.rs index 553fd79f5e50b..5160ceaf48e49 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -1,7 +1,3 @@ -//~ ERROR mismatched types -//~| ERROR mismatched types -//~| ERROR mismatched types -//~| ERROR mismatched types // Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. @@ -51,8 +47,17 @@ trait SomeTrait { impl<'a, T> SomeTrait for &'a Bar { fn dummy1(self: &&'a Bar) { } - fn dummy2(self: &Bar) {} + fn dummy2(self: &Bar) {} //~ ERROR mismatched method receiver + //~^ ERROR mismatched method receiver fn dummy3(self: &&Bar) {} + //~^ ERROR mismatched method receiver + //~| expected type `&'a Bar` + //~| found type `&Bar` + //~| lifetime mismatch + //~| ERROR mismatched method receiver + //~| expected type `&'a Bar` + //~| found type `&Bar` + //~| lifetime mismatch } fn main() { From c046fda312b5a23dd2c531967b6ce241c9cf3d63 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 09:21:54 -0500 Subject: [PATCH 23/26] update test/ui/static-lifetime.stderr with new error message --- src/test/ui/static-lifetime.stderr | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/ui/static-lifetime.stderr b/src/test/ui/static-lifetime.stderr index f73dff4f73d0e..adeabd91302ce 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 From 5d170f0a3c3591b000a0400e7029fc8622144be2 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 09:56:14 -0500 Subject: [PATCH 24/26] add a comment explaining the bugfix to infer::region_inference::add_constraint --- src/librustc/infer/region_inference/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 0bc388a00894c..4c8a72512f1d0 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -633,6 +633,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { debug!("RegionVarBindings: add_constraint({:?})", constraint); + // 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)); From ddc21d567e50437d70f7f56377834135a2d34e6e Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 11:03:27 -0500 Subject: [PATCH 25/26] Don't emit the feature error if it's an invalid self type --- src/librustc_typeck/check/wfcheck.rs | 2 +- src/test/compile-fail/issue-26194.rs | 1 - src/test/compile-fail/ufcs-explicit-self-bad.rs | 3 --- src/test/ui/span/issue-27522.stderr | 11 +---------- 4 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 519392ab26cba..37cf67fe53ef6 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -505,7 +505,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .code(DiagnosticId::Error("E0307".into())) .emit(); - break + return } } diff --git a/src/test/compile-fail/issue-26194.rs b/src/test/compile-fail/issue-26194.rs index 439115a258da7..7ddd56229ceb7 100644 --- a/src/test/compile-fail/issue-26194.rs +++ b/src/test/compile-fail/issue-26194.rs @@ -13,7 +13,6 @@ struct S(String); impl S { fn f(self: *mut S) -> String { self.0 } //~^ ERROR invalid `self` type - //~| ERROR arbitrary `self` types are unstable } 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 5160ceaf48e49..a0d1f2dc3312e 100644 --- a/src/test/compile-fail/ufcs-explicit-self-bad.rs +++ b/src/test/compile-fail/ufcs-explicit-self-bad.rs @@ -17,7 +17,6 @@ struct Foo { impl Foo { fn foo(self: isize, x: isize) -> isize { //~^ ERROR invalid `self` type - //~| ERROR arbitrary `self` types are unstable self.f + x } } @@ -29,12 +28,10 @@ struct Bar { impl Bar { fn foo(self: Bar, x: isize) -> isize { //~^ ERROR invalid `self` type - //~| ERROR arbitrary `self` types are unstable x } fn bar(self: &Bar, x: isize) -> isize { //~^ ERROR invalid `self` type - //~| ERROR arbitrary `self` types are unstable x } } diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr index e3191d7eb22c2..e12fb57f15dc9 100644 --- a/src/test/ui/span/issue-27522.stderr +++ b/src/test/ui/span/issue-27522.stderr @@ -7,14 +7,5 @@ error[E0307]: invalid `self` 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` -error: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/issue-27522.rs:16:22 - | -16 | fn handler(self: &SomeType); - | ^^^^^^^^^ - | - = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable - = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` - -error: aborting due to 2 previous errors +error: aborting due to previous error From 77cd993fd1582680cc01ce86d07e52b2e4b34fec Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 9 Nov 2017 11:42:41 -0500 Subject: [PATCH 26/26] add run-pass tests --- .../run-pass/arbitrary_self_types_silly.rs | 29 ++++++++++++++++ .../run-pass/arbitrary_self_types_struct.rs | 33 +++++++++++++++++++ .../run-pass/arbitrary_self_types_trait.rs | 28 ++++++++++++++++ .../arbitrary_self_types_unsized_struct.rs | 25 ++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 src/test/run-pass/arbitrary_self_types_silly.rs create mode 100644 src/test/run-pass/arbitrary_self_types_struct.rs create mode 100644 src/test/run-pass/arbitrary_self_types_trait.rs create mode 100644 src/test/run-pass/arbitrary_self_types_unsized_struct.rs diff --git a/src/test/run-pass/arbitrary_self_types_silly.rs b/src/test/run-pass/arbitrary_self_types_silly.rs new file mode 100644 index 0000000000000..755a8d7ea294f --- /dev/null +++ b/src/test/run-pass/arbitrary_self_types_silly.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![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 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 0000000000000..961717de0463e --- /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 or the MIT license +// , 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) -> i32 { + self.x + } + + fn y(self: Rc) -> 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 0000000000000..e74d614dd6bd9 --- /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 or the MIT license +// , 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>) -> &'a [i32]; +} + +impl Trait for Vec { + fn trait_method<'a>(self: &'a Box>) -> &'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 0000000000000..8dc40e7aab111 --- /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 or the MIT license +// , 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); + +impl Foo<[u8]> { + fn len(self: Rc) -> usize { + self.0.len() + } +} + +fn main() { + let rc = Rc::new(Foo([1u8,2,3])) as Rc>; + assert_eq!(3, rc.len()); +}