From 153f5a7892274764256862692fa7e2c51474e5d0 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 20 Nov 2018 11:50:50 -0500 Subject: [PATCH 1/3] Stabilize `Rc`, `Arc` and `Pin` as method receivers This lets you write methods using `self: Rc`, `self: Arc`, `self: Pin<&mut Self>`, `self: Pin`, and other combinations involving `Pin` and another stdlib receiver type, without needing the `arbitrary_self_types`. Other user-created receiver types can be used, but they still require the feature flag to use. This is implemented by introducing a new trait, `Receiver`, which the method receiver's type must implement if the `arbitrary_self_types` feature is not enabled. To keep composed receiver types such as `&Arc` unstable, the receiver type is also required to implement `Deref` when the feature flag is not enabled. This lets you use `self: Rc` and `self: Arc` in stable Rust, which was not allowed previously. It was agreed that they would be stabilized in #55786. `self: Pin<&Self>` and other pinned receiver types do not require the `arbitrary_self_types` feature, but they cannot be used on stable because `Pin` still requires the `pin` feature. --- src/liballoc/boxed.rs | 7 +- src/liballoc/lib.rs | 1 + src/liballoc/rc.rs | 5 +- src/liballoc/sync.rs | 5 +- src/libcore/ops/deref.rs | 16 ++ src/libcore/ops/mod.rs | 3 + src/libcore/pin.rs | 5 +- src/librustc/middle/lang_items.rs | 1 + src/librustc_typeck/check/wfcheck.rs | 185 +++++++++++++----- .../arbitrary_self_types_stdlib_pointers.rs | 9 +- .../feature-gate-arbitrary-self-types.rs | 20 +- .../feature-gate-arbitrary-self-types.stderr | 24 +-- ...e-gate-arbitrary_self_types-raw-pointer.rs | 6 +- ...te-arbitrary_self_types-raw-pointer.stderr | 6 +- src/test/ui/privacy/privacy1.rs | 14 ++ src/test/ui/privacy/privacy1.stderr | 34 ++-- 16 files changed, 250 insertions(+), 91 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 83adcce5c742c..f1581310b48fc 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -77,7 +77,9 @@ use core::iter::{Iterator, FromIterator, FusedIterator}; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; -use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState}; +use core::ops::{ + CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState +}; use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; @@ -583,6 +585,9 @@ impl DerefMut for Box { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Box {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Box { type Item = I::Item; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index abacc62c8562b..e00e430fab6ef 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -104,6 +104,7 @@ #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] +#![feature(receiver_trait)] #![feature(specialization)] #![feature(split_ascii_whitespace)] #![feature(staged_api)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 6769a70ddbe0a..3fc70f4ac37a1 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -253,7 +253,7 @@ use core::intrinsics::abort; use core::marker; use core::marker::{Unpin, Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; -use core::ops::Deref; +use core::ops::{Deref, Receiver}; use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -813,6 +813,9 @@ impl Deref for Rc { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Rc {} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// Drops the `Rc`. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index e596694fb9d4b..5573701660812 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -24,7 +24,7 @@ use core::fmt; use core::cmp::Ordering; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val}; -use core::ops::Deref; +use core::ops::{Deref, Receiver}; use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -767,6 +767,9 @@ impl Deref for Arc { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Arc {} + impl Arc { /// Makes a mutable reference into the given `Arc`. /// diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 91a3d77e8b2ef..ff836f4aa69a6 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -177,3 +177,19 @@ pub trait DerefMut: Deref { impl DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { *self } } + +/// Indicates that a struct can be used as a method receiver, without the +/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box`, +/// `Rc`, `&T`, and `Pin

`. +#[cfg_attr(not(stage0), lang = "receiver")] +#[unstable(feature = "receiver_trait", issue = "0")] +#[doc(hidden)] +pub trait Receiver { + // Empty. +} + +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for &T {} + +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for &mut T {} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 785f0733df2b8..06740d2e4cd70 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -178,6 +178,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; +#[unstable(feature = "receiver_trait", issue = "0")] +pub use self::deref::Receiver; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::drop::Drop; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 0ad6e8c7c1c7d..521ce9b5f6b69 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -101,7 +101,7 @@ use fmt; use marker::Sized; -use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn}; +use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; #[doc(inline)] pub use marker::Unpin; @@ -302,6 +302,9 @@ where } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Pin

{} + #[unstable(feature = "pin", issue = "49150")] impl fmt::Debug for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 23ec24d71d2eb..cfcc7c8371976 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -301,6 +301,7 @@ language_item_table! { DerefTraitLangItem, "deref", deref_trait, Target::Trait; DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait; + ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait; FnTraitLangItem, "fn", fn_trait, Target::Trait; FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e24548cfb239f..be8e36afdd620 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,9 +13,8 @@ use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; -use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable}; +use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate}; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::util::ExplicitSelf; use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::middle::lang_items; use rustc::infer::opaque_types::may_define_existential_type; @@ -749,72 +748,164 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, &ty::Binder::bind(self_ty) ); - let self_arg_ty = sig.inputs()[0]; + let receiver_ty = sig.inputs()[0]; - 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.tcx.liberate_late_bound_regions( + let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty); + let receiver_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, - &ty::Binder::bind(self_arg_ty) + &ty::Binder::bind(receiver_ty) ); - let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers(); - - 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(fcx); - if let Some(mut err) = fcx.demand_eqtype_with_origin( - &cause, self_ty, potential_self_ty) { - err.emit(); - } - break - } - } else { + if fcx.tcx.features().arbitrary_self_types { + if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + // report error, arbitrary_self_types was enabled 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)) + span, &format!("invalid `self` type: {:?}", receiver_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())) .emit(); - return } - } - - 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 !fcx.tcx.features().arbitrary_self_types { - match self_kind { - ExplicitSelf::ByValue | - ExplicitSelf::ByReference(_, _) | - ExplicitSelf::ByBox => (), - - ExplicitSelf::ByRawPointer(_) => { + } else { + if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) { + if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { + // report error, would have worked with arbitrary_self_types feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language, - "raw pointer `self` is unstable") + &format!( + "`{}` cannot be used as the type of `self` without \ + the `arbitrary_self_types` feature", + receiver_ty, + ), + ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") + .emit(); + } else { + // report error, would not have worked with arbitrary_self_types + fcx.tcx.sess.diagnostic().mut_span_err( + span, &format!("invalid `self` type: {:?}", receiver_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())) .emit(); } + } + } +} - ExplicitSelf::Other => { - 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(); +fn receiver_is_valid<'fcx, 'tcx, 'gcx>( + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + span: Span, + receiver_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + arbitrary_self_types_enabled: bool, +) -> bool { + let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver); + + let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); + + if can_eq_self(receiver_ty) { + if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { + err.emit(); + } + return true + } + + let mut autoderef = fcx.autoderef(span, receiver_ty); + + if arbitrary_self_types_enabled { + autoderef = autoderef.include_raw_pointers(); + } + + // skip the first type, we know its not equal to `self_ty` + autoderef.next(); + + let potential_self_ty = loop { + if let Some((potential_self_ty, _)) = autoderef.next() { + debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`", + potential_self_ty, self_ty); + + if can_eq_self(potential_self_ty) { + break potential_self_ty + } + } else { + debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", + receiver_ty, self_ty); + return false + } + }; + + if !arbitrary_self_types_enabled { + // check that receiver_ty: Receiver + + let receiver_trait_def_id = match fcx.tcx.lang_items().receiver_trait() { + Some(did) => did, + None => { + debug!("receiver_is_valid: missing Receiver trait"); + return false } + }; + + let receiver_trait_ref = ty::TraitRef{ + def_id: receiver_trait_def_id, + substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), + }; + + let receiver_obligation = traits::Obligation::new( + cause.clone(), + fcx.param_env, + receiver_trait_ref.to_predicate() + ); + + if !fcx.predicate_must_hold(&receiver_obligation) { + debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait", + receiver_ty); + return false + } + + let deref_trait_def_id = match fcx.tcx.lang_items().deref_trait() { + Some(did) => did, + None => { + debug!("receiver_is_valid: missing Deref trait"); + return false + } + }; + + let deref_trait_ref = ty::TraitRef { + def_id: deref_trait_def_id, + substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), + }; + + let projection_ty = ty::ProjectionTy::from_ref_and_name( + fcx.tcx, deref_trait_ref, ast::Ident::from_str("Target") + ); + + let projection_predicate = ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, ty: self_ty + }).to_predicate(); + + let deref_obligation = traits::Obligation::new( + cause.clone(), + fcx.param_env, + projection_predicate, + ); + + if !fcx.predicate_must_hold(&deref_obligation) { + debug!("receiver_is_valid: type `{:?}` does not directly deref to `{:?}`", + receiver_ty, self_ty); + return false } } + + if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) { + err.emit(); + } + + autoderef.finalize(fcx); + + true } fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs index 80a7ce9691126..6ec70bb8c09c8 100644 --- a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs +++ b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(arbitrary_self_types)] #![feature(pin)] #![feature(rustc_attrs)] @@ -23,6 +22,7 @@ trait Trait { fn by_arc(self: Arc) -> i64; fn by_pin_mut(self: Pin<&mut Self>) -> i64; fn by_pin_box(self: Pin>) -> i64; + fn by_pin_pin_pin_ref(self: Pin>>) -> i64; } impl Trait for i64 { @@ -38,6 +38,9 @@ impl Trait for i64 { fn by_pin_box(self: Pin>) -> i64 { *self } + fn by_pin_pin_pin_ref(self: Pin>>) -> i64 { + *self + } } fn main() { @@ -53,4 +56,8 @@ fn main() { let pin_box = Into::>>::into(Box::new(4i64)) as Pin>; assert_eq!(4, pin_box.by_pin_box()); + + let value = 5i64; + let pin_pin_pin_ref = Pin::new(Pin::new(Pin::new(&value))) as Pin>>; + assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref()); } diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs index ff0306f199310..84cd5c2bffa62 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs @@ -8,20 +8,32 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; +use std::{ + ops::Deref, +}; + +struct Ptr(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} trait Foo { - fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without } struct Bar; impl Foo for Bar { - fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without } impl Bar { - fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable + fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index ea259aa22adfb..c70774b3710de 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -1,26 +1,26 @@ -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:14:18 +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | -LL | fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without + | ^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:20:18 +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:32:18 | -LL | fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without + | ^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:24:18 +error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:36:18 | -LL | fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the + | ^^^^^^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs index 29e51727edcfd..6d42460ba5684 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs @@ -12,17 +12,17 @@ struct Foo; impl Foo { fn foo(self: *const Self) {} - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const Foo` cannot be used as the type of `self` without } trait Bar { fn bar(self: *const Self); - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const Self` cannot be used as the type of `self` without } impl Bar for () { fn bar(self: *const Self) {} - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const ()` cannot be used as the type of `self` without } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index 5ed9a0f4ed040..b8cc7dee9867d 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -1,4 +1,4 @@ -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:19:18 | LL | fn bar(self: *const Self); @@ -7,7 +7,7 @@ LL | fn bar(self: *const Self); = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | LL | fn foo(self: *const Self) {} @@ -16,7 +16,7 @@ LL | fn foo(self: *const Self) {} = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:24:18 | LL | fn bar(self: *const Self) {} diff --git a/src/test/ui/privacy/privacy1.rs b/src/test/ui/privacy/privacy1.rs index 9aff4bbc41c9c..c336cc6299eb5 100644 --- a/src/test/ui/privacy/privacy1.rs +++ b/src/test/ui/privacy/privacy1.rs @@ -17,6 +17,20 @@ pub trait Sized {} #[lang="copy"] pub trait Copy {} +#[lang="deref"] +pub trait Deref { + type Target; +} + +#[lang="receiver"] +pub trait Receiver: Deref {} + +impl<'a, T> Deref for &'a T { + type Target = T; +} + +impl<'a, T> Receiver for &'a T {} + mod bar { // shouldn't bring in too much pub use self::glob::*; diff --git a/src/test/ui/privacy/privacy1.stderr b/src/test/ui/privacy/privacy1.stderr index d6197575447e6..54e01cca6c43a 100644 --- a/src/test/ui/privacy/privacy1.stderr +++ b/src/test/ui/privacy/privacy1.stderr @@ -1,101 +1,101 @@ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:128:18 + --> $DIR/privacy1.rs:142:18 | LL | use bar::baz::{foo, bar}; | ^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:136:18 + --> $DIR/privacy1.rs:150:18 | LL | use bar::baz; | ^^^ error[E0603]: module `i` is private - --> $DIR/privacy1.rs:160:20 + --> $DIR/privacy1.rs:174:20 | LL | use self::foo::i::A; //~ ERROR: module `i` is private | ^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:100:16 + --> $DIR/privacy1.rs:114:16 | LL | ::bar::baz::A::foo(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:101:16 + --> $DIR/privacy1.rs:115:16 | LL | ::bar::baz::A::bar(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:103:16 + --> $DIR/privacy1.rs:117:16 | LL | ::bar::baz::A.foo2(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:104:16 + --> $DIR/privacy1.rs:118:16 | LL | ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: trait `B` is private - --> $DIR/privacy1.rs:108:16 + --> $DIR/privacy1.rs:122:16 | LL | ::bar::B::foo(); //~ ERROR: trait `B` is private | ^ error[E0603]: function `epriv` is private - --> $DIR/privacy1.rs:114:20 + --> $DIR/privacy1.rs:128:20 | LL | ::bar::epriv(); //~ ERROR: function `epriv` is private | ^^^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:123:16 + --> $DIR/privacy1.rs:137:16 | LL | ::bar::baz::foo(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: module `baz` is private - --> $DIR/privacy1.rs:124:16 + --> $DIR/privacy1.rs:138:16 | LL | ::bar::baz::bar(); //~ ERROR: module `baz` is private | ^^^ error[E0603]: trait `B` is private - --> $DIR/privacy1.rs:152:17 + --> $DIR/privacy1.rs:166:17 | LL | impl ::bar::B for f32 { fn foo() -> f32 { 1.0 } } | ^ error[E0624]: method `bar` is private - --> $DIR/privacy1.rs:73:9 + --> $DIR/privacy1.rs:87:9 | LL | self::baz::A::bar(); //~ ERROR: method `bar` is private | ^^^^^^^^^^^^^^^^^ error[E0624]: method `bar` is private - --> $DIR/privacy1.rs:91:5 + --> $DIR/privacy1.rs:105:5 | LL | bar::A::bar(); //~ ERROR: method `bar` is private | ^^^^^^^^^^^ error[E0624]: method `bar` is private - --> $DIR/privacy1.rs:98:9 + --> $DIR/privacy1.rs:112:9 | LL | ::bar::A::bar(); //~ ERROR: method `bar` is private | ^^^^^^^^^^^^^ error[E0624]: method `bar` is private - --> $DIR/privacy1.rs:101:9 + --> $DIR/privacy1.rs:115:9 | LL | ::bar::baz::A::bar(); //~ ERROR: module `baz` is private | ^^^^^^^^^^^^^^^^^^ error[E0624]: method `bar2` is private - --> $DIR/privacy1.rs:104:23 + --> $DIR/privacy1.rs:118:23 | LL | ::bar::baz::A.bar2(); //~ ERROR: module `baz` is private | ^^^^ From 1d93c6149dd70bf16c45f3238fa74241c336e02d Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 14 Dec 2018 01:27:49 -0500 Subject: [PATCH 2/3] add a doc comment on `receiver_is_valid` --- src/librustc_typeck/check/wfcheck.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index be8e36afdd620..d35a4dfe0b91d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -795,6 +795,14 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } } +/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If +/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly +/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more +/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref`. +/// +/// NB: there are cases this function returns `true` but then causes an error to be raised later, +/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the +/// wrong lifetime. fn receiver_is_valid<'fcx, 'tcx, 'gcx>( fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, From 286503ace2fd1fc8ac8bf8aa10378fb93763d99f Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 16 Dec 2018 16:47:37 -0500 Subject: [PATCH 3/3] Refactor and add comments to code in receiver_is_valid also updated some error messages removed the code manually checking for `receiver_ty: Deref`, in favour of using autoderef but only doing one iteration. This will cause error messages to be more consistent. Before, a "mismatched method receiver" error would be emitted when `receiver_ty` was valid except for a lifetime parameter, but only when `feature(arbitrary_self_types)` was enabled, and without the feature flag the error would be "uncoercible receiver". Now it emits "mismatched method receiver" in both cases. --- src/librustc_typeck/check/wfcheck.rs | 91 +++++++------------ src/test/ui/span/issue-27522.rs | 2 +- src/test/ui/span/issue-27522.stderr | 4 +- src/test/ui/ufcs/ufcs-explicit-self-bad.rs | 6 +- .../ui/ufcs/ufcs-explicit-self-bad.stderr | 12 +-- 5 files changed, 46 insertions(+), 69 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index d35a4dfe0b91d..e74b1ae47e39d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -760,8 +760,8 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { // report error, arbitrary_self_types was enabled fcx.tcx.sess.diagnostic().mut_span_err( - span, &format!("invalid `self` type: {:?}", receiver_ty) - ).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) + span, &format!("invalid method receiver type: {:?}", receiver_ty) + ).note("type of `self` must be `Self` or a type that dereferences to it") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .code(DiagnosticId::Error("E0307".into())) .emit(); @@ -785,8 +785,8 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, } else { // report error, would not have worked with arbitrary_self_types fcx.tcx.sess.diagnostic().mut_span_err( - span, &format!("invalid `self` type: {:?}", receiver_ty) - ).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) + span, &format!("invalid method receiver type: {:?}", receiver_ty) + ).note("type must be `Self` or a type that dereferences to it") .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .code(DiagnosticId::Error("E0307".into())) .emit(); @@ -800,9 +800,9 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, /// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more /// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref`. /// -/// NB: there are cases this function returns `true` but then causes an error to be raised later, +/// NB: there are cases this function returns `true` but causes an error to be emitted, /// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the -/// wrong lifetime. +/// wrong lifetime. Be careful of this if you are calling this function speculatively. fn receiver_is_valid<'fcx, 'tcx, 'gcx>( fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, @@ -814,6 +814,7 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); + // `self: Self` is always valid if can_eq_self(receiver_ty) { if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) { err.emit(); @@ -823,32 +824,47 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( let mut autoderef = fcx.autoderef(span, receiver_ty); + // the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self` if arbitrary_self_types_enabled { autoderef = autoderef.include_raw_pointers(); } - // skip the first type, we know its not equal to `self_ty` + // the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it. autoderef.next(); - let potential_self_ty = loop { + // keep dereferencing `receiver_ty` until we get to `self_ty` + loop { if let Some((potential_self_ty, _)) = autoderef.next() { debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`", potential_self_ty, self_ty); if can_eq_self(potential_self_ty) { - break potential_self_ty + autoderef.finalize(fcx); + + if let Some(mut err) = fcx.demand_eqtype_with_origin( + &cause, self_ty, potential_self_ty + ) { + err.emit(); + } + + break } } else { debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); return false } - }; - if !arbitrary_self_types_enabled { - // check that receiver_ty: Receiver + // without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to + // `self_ty`. Enforce this by only doing one iteration of the loop + if !arbitrary_self_types_enabled { + return false + } + } - let receiver_trait_def_id = match fcx.tcx.lang_items().receiver_trait() { + // without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver` + if !arbitrary_self_types_enabled { + let trait_def_id = match fcx.tcx.lang_items().receiver_trait() { Some(did) => did, None => { debug!("receiver_is_valid: missing Receiver trait"); @@ -856,63 +872,24 @@ fn receiver_is_valid<'fcx, 'tcx, 'gcx>( } }; - let receiver_trait_ref = ty::TraitRef{ - def_id: receiver_trait_def_id, + let trait_ref = ty::TraitRef{ + def_id: trait_def_id, substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), }; - let receiver_obligation = traits::Obligation::new( + let obligation = traits::Obligation::new( cause.clone(), fcx.param_env, - receiver_trait_ref.to_predicate() + trait_ref.to_predicate() ); - if !fcx.predicate_must_hold(&receiver_obligation) { + if !fcx.predicate_must_hold(&obligation) { debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait", receiver_ty); return false } - - let deref_trait_def_id = match fcx.tcx.lang_items().deref_trait() { - Some(did) => did, - None => { - debug!("receiver_is_valid: missing Deref trait"); - return false - } - }; - - let deref_trait_ref = ty::TraitRef { - def_id: deref_trait_def_id, - substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), - }; - - let projection_ty = ty::ProjectionTy::from_ref_and_name( - fcx.tcx, deref_trait_ref, ast::Ident::from_str("Target") - ); - - let projection_predicate = ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, ty: self_ty - }).to_predicate(); - - let deref_obligation = traits::Obligation::new( - cause.clone(), - fcx.param_env, - projection_predicate, - ); - - if !fcx.predicate_must_hold(&deref_obligation) { - debug!("receiver_is_valid: type `{:?}` does not directly deref to `{:?}`", - receiver_ty, self_ty); - return false - } - } - - if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) { - err.emit(); } - autoderef.finalize(fcx); - true } diff --git a/src/test/ui/span/issue-27522.rs b/src/test/ui/span/issue-27522.rs index 1e3eba4bf3631..11c90833e7181 100644 --- a/src/test/ui/span/issue-27522.rs +++ b/src/test/ui/span/issue-27522.rs @@ -13,7 +13,7 @@ struct SomeType {} trait Foo { - fn handler(self: &SomeType); //~ ERROR invalid `self` type + fn handler(self: &SomeType); //~ ERROR invalid method receiver type } fn main() {} diff --git a/src/test/ui/span/issue-27522.stderr b/src/test/ui/span/issue-27522.stderr index 9b61ecae6512e..767b99a92cb2d 100644 --- a/src/test/ui/span/issue-27522.stderr +++ b/src/test/ui/span/issue-27522.stderr @@ -1,7 +1,7 @@ -error[E0307]: invalid `self` type: &SomeType +error[E0307]: invalid method receiver type: &SomeType --> $DIR/issue-27522.rs:16:22 | -LL | fn handler(self: &SomeType); //~ ERROR invalid `self` type +LL | fn handler(self: &SomeType); //~ ERROR invalid method receiver type | ^^^^^^^^^ | = note: type must be `Self` or a type that dereferences to it diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs index a0d1f2dc3312e..f87541b56acf9 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs @@ -16,7 +16,7 @@ struct Foo { impl Foo { fn foo(self: isize, x: isize) -> isize { - //~^ ERROR invalid `self` type + //~^ ERROR invalid method receiver type self.f + x } } @@ -27,11 +27,11 @@ struct Bar { impl Bar { fn foo(self: Bar, x: isize) -> isize { - //~^ ERROR invalid `self` type + //~^ ERROR invalid method receiver type x } fn bar(self: &Bar, x: isize) -> isize { - //~^ ERROR invalid `self` type + //~^ ERROR invalid method receiver type x } } diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr index fce74605cad38..a229dabcce4a4 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.stderr @@ -1,28 +1,28 @@ -error[E0307]: invalid `self` type: isize +error[E0307]: invalid method receiver type: isize --> $DIR/ufcs-explicit-self-bad.rs:18:18 | LL | fn foo(self: isize, x: isize) -> isize { | ^^^^^ | - = note: type must be `Foo` or a type that dereferences to it + = note: type must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0307]: invalid `self` type: Bar +error[E0307]: invalid method receiver type: Bar --> $DIR/ufcs-explicit-self-bad.rs:29:18 | LL | fn foo(self: Bar, x: isize) -> isize { | ^^^^^^^^^^ | - = note: type must be `Bar` or a type that dereferences to it + = note: type must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0307]: invalid `self` type: &Bar +error[E0307]: invalid method receiver type: &Bar --> $DIR/ufcs-explicit-self-bad.rs:33:18 | LL | fn bar(self: &Bar, x: isize) -> isize { | ^^^^^^^^^^^ | - = note: type must be `Bar` or a type that dereferences to it + = note: type must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` error[E0308]: mismatched method receiver