-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arbitrary self types v2 #3519
Arbitrary self types v2 #3519
Conversation
This PR suggests small changes to the existing unstable "aribtrary self types" feature to make it more flexible. In particular, it suggests driving this feature from a new (ish) "Receiver" trait instead of from Deref, but to maintain compatibility by having a blanket implementation for all Deref types. This is a squashed commit of much work by various folks including Johann Hemmann, Lukas Wirth, Mads Marquart and myself. Thanks also to David Hewitt and Manish Goregaokar for feedback. Co-authored-by: Johann Hemmann <johann.hemmann@code.berlin>
text/3519-arbitrary-self-types-v2.md
Outdated
|
||
We don't want to encourage the use of raw pointers, and would prefer rather that raw pointers are wrapped in a custom smart pointer that encodes and documents the invariants. So, there's an argument not to add the raw pointer support. | ||
|
||
However, the current unstable `arbitrary_self_types` feature provides support for raw pointer receivers, and with years of experience no major concerns have been spotted. We would prefer not to deviate from the existing proposal more than necessary. Moreover, we are led to believe that raw pointer receivers are quite important for the future of safe Rust, because stacked borrows makes it illegal to materialize references in many positions, and there are a lot of operations (like going from a raw pointer to a raw pointer to a field) where users don't need to or want to do that. We think the utility of including raw pointer receivers outweighs the risks of tempting people to over-use raw pointers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't that mean that adding methods on *const T
, like add()
, is a breaking change? How has this been dealt with so far?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. There are various Rust standard library types - Box
, Arc
etc. - where by policy no new methods are added because it would be a breaking change. Instead, associated functions are added.
If arbitrary self types is enabled (either the existing nightly unstable version, or our slightly tweaked version here) then that policy would need to be extended to the raw pointer types as well.
The Rust community therefore needs to decide which is higher priority:
- being able to add new methods to raw pointer types; or
- being able to receive method calls by raw pointer.
Unless someone can see some workaround or compromise?
@Manishearth hello, I think you were especially keen that arbitrary self types continues to support raw pointers. Do you have any views?
(Personally I think this might be a good argument to enable arbitrary self types without raw pointers, and therefore to require people to write their own newtype wrappers if they want method dispatch).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(there's a little bit more discussion of this in this comment thread below which I'm going to close to avoid duplication)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to reply to your comment about changing priority: I think this new problem is a much better problem. The original issue is "the pointer type *const T
can't add any new methods ever", the new issue is "crate A can add foo(*const Self)
methods, except that if they're from the set of known *const T
methods, this is a major semver change". This is a bit surprising but highly manageable.
What worries me more is the high confusion cost of making method resolution more complicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still thinking this through but I wanted to note that we Rust doesn't current shadow things invisibly; instead it gives an error message if there's ambiguity.
- For arbitrary self types which are not raw pointers: we show the ambiguity as an error.
- For arbitrary self types which are raw pointers, we show similar errors if there are ambiguities, and we even warn if there are known upcoming future ambiguities:
= warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior!
= note: for more information, see issue #48919 <https://github.com/rust-lang/rust/issues/48919>
= help: call with fully qualified syntax `MyType::addr(...)` to keep using the current method
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable `ptr::const_ptr::<impl *const T>::addr`
= note: `#[warn(unstable_name_collisions)]` on by default
This RFC should be more explicit somewhere about the existence of these errors and warnings, especially in the Method Shadowing section - I'll adjust.
Of course, this doesn't solve the issue here: if Rust adds a new <raw pointer>::repaint()
method, that will cause downstream crates to cease building if they had:
struct Bedroom;
impl Bedroom {
fn repaint(self: *const Bedroom) {}
}
@Nadrieril 's proposal, as I understand it, is that if method resolution does result in ambiguities in such a situation, where raw pointers are involved, we don't show an error for the ambiguity but instead automatically pick Bedroom::repaint
and show a warning.
I do agree that seems to be manageable and I don't think it makes method resolution cognitively more complex, because any such situations will result in a nice clear warning explaining the situation. It might make the code significantly more complex - I'll look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We mustn't change what type would be picked by Deref indeed. My guess is that the rule we want would apply only in case of an ambiguity that involves a Receiver type, and would favor the self: P<Self>
method over P
's inherent methods. This shouldn't be a breaking change if there isn't a Receiver involved, or if the Receiver has no inherent methods (like Box or Rc). I'd need to write it down clearly to be fully convinced that works though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had an example the other day: say x: &Arc<Box<T>>
and I call x.foo()
. Here are the methods that could be called, in my proposed order of priority ("most specific first"):
foo(&Arc<Box<Self>>)
onT
foo(&Arc<Self>)
onBox<T>
foo(&Box<Self>)
onT
foo(&self)
onArc<T>
foo(&self)
onBox<T>
foo(&self)
onT
- any trait methods
If we want "adding inherent methods to a Receiver type is not a breaking change", we need 4, 5 and 6 to be the lowest priority before trait methods. Question is: does this order break anything compared to what's allowed on stable today?
The current implementation of arbitrary_self_types
sometimes errors on some of these combinations. The interesting cases for us is when 3 and 5 are available, or 1 and 4. This currently errors as ambiguous; we would instead pick 3 and 1 respectively.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok so I did a thorough experiment (try out my madness here). It appears the algorithm picks 4 over 3 in my list above, which could appear to break my proposal. The rest of the order is ok, so today's method resolution algorithm is compatible with this ordering:
a. foo(&Arc<Box<Self>>)
on T
b. foo(&Arc<Self>)
on Box<T>
c. foo(&self)
on Arc<T>
d. foo(&Box<Self>)
on T
e. foo(&self)
on Box<T>
f. foo(&self)
on T
However! All is still fine. Indeed, if Arc
was not Deref
, we would only consider the following cases:
a. foo(&Arc<Box<Self>>)
on T
b. foo(&Arc<Self>)
on Box<T>
c. foo(&self)
on Arc<T>
Here adding an inherent method to Arc
would not be a breaking change. The reason adding an inherent method to Arc
is breaking is because Arc: Deref
, and we already know that adding methods to Deref
types is a breaking change.
In short: if we take the current implementation of arbitrary_self_types
and simply accept more cases that are currently errors, we can get the order above and the property that "adding inherent methods to a Receiver type is not a breaking change".
Moreover! Given that the only stable Receiver
types don't have inherent methods (I think, right?), I believe we can even change this order a bit without breakage. It will only break users of the unstable arbitrary_self_types
feature in that one corner case. So we can pick my initial "most specific first" order too if we prefer.
I think that proves that we're good? Did I miss anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I grepped through std: the stable Receiver
s are exactly Box
, Rc
, Arc
, Pin
, &T
, and &mut T
. None of these have inherent methods, except Pin
, which has e.g. Pin::as_ref()
. So we can't change the order. But we can still do the first thing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Manishearth hello, I think you were especially keen that arbitrary self types continues to support raw pointers. Do you have any views?
Missed this. Yeah, I think it's important for the ergonomics of unsafe code. Wrapper types are an okay workaround, as are free functions.
Raw pointers are basically the native rust version of "I want to be able to hold a CppPointer<T>
without breaking it", so it would be ideal for
I think #[fundamental]
's behavior may be useful for dealing with raw pointer receivers: I don't think there's anything new here that doesn't apply to &T
as well. I think it's fine for Rust to need new editions for new methods on *const T
; and there are some ways of making that work even without editions.
text/3519-arbitrary-self-types-v2.md
Outdated
A blanket implementation is provided for any type that implements `Deref`: | ||
|
||
```rust | ||
impl<P: ?Sized, T: ?Sized> Receiver for P | ||
where | ||
P: Deref<Target = T>, | ||
{ | ||
type Target = T; | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is actually a problem here that I didn't realize back when we talked about this. Implementing Receiver
is effectively a promise to not add any new methods to the implementing type (given the reasons already outlined here, as adding methods could break downstream users for these kinds of types). This impl means, this promise now propagates to Deref
implementations as well which seems like a very much unwanted side effect, especially given all the current Deref
impls out there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this already true of Deref
implementations? Adding a new method to a type A
implementing Deref<Target = B>
will shadow a method of the same name on B
, so I think there is no change in semantics by adding Receiver
to the mix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EDIT: original link mistakenly missed closing parenthesis.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No because you can't add inherent impls to a foreign type, so you can't add new inherent methods to them (ignoring fundamental types). With the Receiver
trait you can kind of add new inherent methods to foreign types though.
//- crate: foo
pub struct Foo<T>(pub T);
impl<T> Receiver for Foo<T> {
type Target = T;
}
//- crate: bar (depends on foo)
use foo::Foo;
struct Bar;
impl Bar {
fn foobar(self: Foo<Bar>) {}
}
fn main() {
Foo(Bar).foobar();
}
Adding a fn foobar(self)
method to Foo
would break the crate bar
in this case, so adding a method to a Receiver
implementing type is a breaking change. And since Deref
here implies implementing Receiver
, the same issue arises from just Deref
implementations, that is the same issue would occur if instead of the Receiver
impl in that example we had
impl<T> Deref for Foo<T> {
type Target = T;
fn deref(&self) -> &Self::Target { &self.0 }
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discarding Receiver
from this RFC for the moment, I'm still missing what makes you take the stance that Deref
implementors on today's Rust don't already carry the same promise not to add new methods. As far as I understand, this problem already exists with Deref
, so adding Receiver
to all Deref
types changes nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also agree that it's a breaking but non-major change. Adding a blanket impl for an existing trait, implementing a new method on an existing type, and newly implementing a trait for an existing type are all breaking changes (and ones deemed non-major) regardless of arbitrary self types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. Doesn't Deref
already have this exact problem though? That's exactly why Box
/Rc
/etc have no normal methods, since adding a fn foo(&self)
to Box
would break x.foo()
on x: Box<Foo>
if Foo
has fn foo(&self)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how Deref
already has this problem (unless you are referring to the current Deref
version of this feature prior to this RFC). Box
, Rc
, Pin
etc have htis problem because they are already allowed as arbitrary receivers as they have been special cased. Deref
has no say in that. With the RFC as written, all Deref
implementations will have this problem. Anyways, even if this is considered a minor breakage only (which I'd argue against personally, it very much feels like a major breakage to me), the RFC should definitely talk about this, both in that implementing Receiver
has this semver problem as well as that the blanket impl will extend it to Deref
impls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I mean plain Deref. Let me spell it out:
//- crate: foo (depends on nothing)
pub struct Foo<T>(pub T);
impl<T> Deref for Foo<T> {
type Target = T;
fn deref(...) {...}
}
//- crate: bar (depends on nothing)
pub struct Bar;
impl Bar {
pub fn foobar(&self) {}
}
//- crate: qux (depends on bar and foo)
fn main() {
Foo(Bar).foobar(); // resolves to `Bar::foobar`
}
Now, if crate foo adds the following:
impl<T> Foo<T> {
pub fn foobar(&self) {}
}
then Foo(Bar).foobar()
in crate qux now resolves to Foo<T>::foobar
. I imagine this is a major breaking change since now qux could still compile yet be using a completely different function.
This is the same problem; Deref
pointers already have to deal with it today. Hence I conclude: adding Receiver into the mix should not change anything, all is good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @Nadrieril, this is a non-issue for this RFC, since the problem is already present on Deref
types.
The RFC actually has a section that talks about this, I've updated that in #3519 (review) to include a few more references to external resources that further explain the problem.
I'll also link to rust-lang/rust-clippy#11820, which proposes a new clippy lint to catch inherent methods on smart pointers, to hopefully help implementers of such types (including in the future, implementers of Receiver
) to avoid this pitfall.
another good use case for arbitrary self types that may be worth mentioning in the rfc: #[derive(Default)]
pub struct GCArena {
objects: Vec<Rc<dyn Any>>,
}
impl GCArena {
pub fn alloc<T: 'static>(&mut self, value: T) -> Gc<T> {
let rc: Rc<T> = Rc::new(value);
let weak = Rc::downgrade(&rc);
self.objects.push(rc);
Gc(weak)
}
}
#[derive(Clone)]
pub struct Gc<T: 'static + ?Sized>(Weak<T>);
impl PartialEq for Gc<T: 'static + ?Sized> {
fn eq(&self, other: &Gc<T>) -> bool {
self.0.ptr_eq(&other.0)
}
}
impl Eq for Gc<T: 'static + ?Sized> {}
impl Hash for Gc<T: 'static + ?Sized> {
fn hash<H: Hasher>(&self, state: &mut H) {
(self.0.as_ptr() as *const ()).hash(state);
}
}
impl<T: 'static + ?Sized> Receiver for Gc<T> {
type Target = T;
}
impl<T: 'static + ?Sized> Receiver for Gc<T> {
pub fn get(&self) -> Rc<T> {
self.0.upgrade().expect("GCArena has been dropped")
}
}
// demo of using Gc:
pub struct Node<T> {
pub edges: Vec<Gc<Node<T>>>,
pub data: T,
}
impl<T> Node<T> {
pub fn walk(self: &Gc<Self>, seen: &mut HashSet<Gc<Self>>, f: &mut impl FnMut(&Gc<Self>)) {
if seen.insert(self.clone()) {
f(self);
for i in &self.get().edges {
i.walk(seen, f);
}
}
}
} |
@programmerjake I think this is now covered by the paragraph I wrote that is now part of the RFC?
This feels like the same case you present: you want the ability to both access the inner type and clone the smart pointer, and simply accessing the inner type isn't enough. |
well, i had intended to demonstrate a type where you can't just impl another use case: a type where the inner value doesn't exist locally, e.g. for RPC with promise pipelining: pub struct Id(u32);
pub struct Promise<T>(Id, PhantomData<T>);
impl<T> Receiver for Promise<T> {
type Target = T;
}
pub struct MyRemoteData;
pub struct SomeIntermediate;
impl MyRemoteData {
pub fn get() -> Promise<Self> {
...
}
pub fn foo(self: Promise<Self>, a: i32) -> Promise<SomeIntermediate> {
...
}
}
impl SomeIntermediate {
pub fn bar(self: Promise<Self>) -> Promise<()> {
...
}
}
pub async fn demo() {
MyRemoteData::get().foo(5).bar().await;
} |
The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in rust-lang#129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc<Self> and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR is a second attempt at achieving this, based on producing a new well-formedness checking context which is only aware of the type params of the impl block, not of the method itself. It doesn't currently work because it turns out we do need some method params under some circumstances, but raising it for completeness. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
The `arbitrary_self_types` RFC [1] is accepted and the feature is being worked on [2]. As part of the RFC, a new `Receiver` trait is to be added, and it will be automatically implemented for all types that have `Deref` implementation. This is different from the existing `Receiver` trait that we use, which is a custom implementation that opts-in a type into being used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net>
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
The term "receiver" means that a type can be used as the type of `self`, and thus enables method call syntax `foo.bar()` instead of `Foo::bar(foo)`. Stable Rust as of today (1.81) enables a limited selection of types (primitives and types in std, e.g. `Box` and `Arc`) to be used as receivers, while custom types cannot. We want the kernel `Arc` type to have the same functionality as the Rust std `Arc`, so we use the `Receiver` trait (gated behind `receiver_trait` unstable feature) to gain the functionality. The `arbitrary_self_types` RFC [1] (tracking issue [2]) is accepted and it will allow all types that implement a new `Receiver` trait (different from today's unstable trait) to be used as receivers. This trait will be automatically implemented for all `Deref` types, which include our `Arc` type, so we no longer have to opt-in to be used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. This feature gate is introduced in 1.23.0. It used to enable both `Deref` types and raw pointer types to be used as receivers, but the latter is now split into a different feature gate in Rust 1.83 nightly. We do not need receivers on raw pointers so this change would not affect us and usage of `arbitrary_self_types` feature would work for all Rust versions that we support (>=1.78). Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net>
The term "receiver" means that a type can be used as the type of `self`, and thus enables method call syntax `foo.bar()` instead of `Foo::bar(foo)`. Stable Rust as of today (1.81) enables a limited selection of types (primitives and types in std, e.g. `Box` and `Arc`) to be used as receivers, while custom types cannot. We want the kernel `Arc` type to have the same functionality as the Rust std `Arc`, so we use the `Receiver` trait (gated behind `receiver_trait` unstable feature) to gain the functionality. The `arbitrary_self_types` RFC [1] (tracking issue [2]) is accepted and it will allow all types that implement a new `Receiver` trait (different from today's unstable trait) to be used as receivers. This trait will be automatically implemented for all `Deref` types, which include our `Arc` type, so we no longer have to opt-in to be used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. This feature gate is introduced in 1.23.0. It used to enable both `Deref` types and raw pointer types to be used as receivers, but the latter is now split into a different feature gate in Rust 1.83 nightly. We do not need receivers on raw pointers so this change would not affect us and usage of `arbitrary_self_types` feature would work for all Rust versions that we support (>=1.78). Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240915132734.1653004-1-gary@garyguo.net Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
The term "receiver" means that a type can be used as the type of `self`, and thus enables method call syntax `foo.bar()` instead of `Foo::bar(foo)`. Stable Rust as of today (1.81) enables a limited selection of types (primitives and types in std, e.g. `Box` and `Arc`) to be used as receivers, while custom types cannot. We want the kernel `Arc` type to have the same functionality as the Rust std `Arc`, so we use the `Receiver` trait (gated behind `receiver_trait` unstable feature) to gain the functionality. The `arbitrary_self_types` RFC [1] (tracking issue [2]) is accepted and it will allow all types that implement a new `Receiver` trait (different from today's unstable trait) to be used as receivers. This trait will be automatically implemented for all `Deref` types, which include our `Arc` type, so we no longer have to opt-in to be used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. This feature gate is introduced in 1.23.0. It used to enable both `Deref` types and raw pointer types to be used as receivers, but the latter is now split into a different feature gate in Rust 1.83 nightly. We do not need receivers on raw pointers so this change would not affect us and usage of `arbitrary_self_types` feature would work for all Rust versions that we support (>=1.78). Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240915132734.1653004-1-gary@garyguo.net Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
The term "receiver" means that a type can be used as the type of `self`, and thus enables method call syntax `foo.bar()` instead of `Foo::bar(foo)`. Stable Rust as of today (1.81) enables a limited selection of types (primitives and types in std, e.g. `Box` and `Arc`) to be used as receivers, while custom types cannot. We want the kernel `Arc` type to have the same functionality as the Rust std `Arc`, so we use the `Receiver` trait (gated behind `receiver_trait` unstable feature) to gain the functionality. The `arbitrary_self_types` RFC [1] (tracking issue [2]) is accepted and it will allow all types that implement a new `Receiver` trait (different from today's unstable trait) to be used as receivers. This trait will be automatically implemented for all `Deref` types, which include our `Arc` type, so we no longer have to opt-in to be used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. This feature gate is introduced in 1.23.0. It used to enable both `Deref` types and raw pointer types to be used as receivers, but the latter is now split into a different feature gate in Rust 1.83 nightly. We do not need receivers on raw pointers so this change would not affect us and usage of `arbitrary_self_types` feature would work for all Rust versions that we support (>=1.78). Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240915132734.1653004-1-gary@garyguo.net Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
The term "receiver" means that a type can be used as the type of `self`, and thus enables method call syntax `foo.bar()` instead of `Foo::bar(foo)`. Stable Rust as of today (1.81) enables a limited selection of types (primitives and types in std, e.g. `Box` and `Arc`) to be used as receivers, while custom types cannot. We want the kernel `Arc` type to have the same functionality as the Rust std `Arc`, so we use the `Receiver` trait (gated behind `receiver_trait` unstable feature) to gain the functionality. The `arbitrary_self_types` RFC [1] (tracking issue [2]) is accepted and it will allow all types that implement a new `Receiver` trait (different from today's unstable trait) to be used as receivers. This trait will be automatically implemented for all `Deref` types, which include our `Arc` type, so we no longer have to opt-in to be used as receiver. To prepare us for the change, remove the `Receiver` implementation and the associated feature. To still allow `Arc` and others to be used as method receivers, turn on `arbitrary_self_types` feature instead. This feature gate is introduced in 1.23.0. It used to enable both `Deref` types and raw pointer types to be used as receivers, but the latter is now split into a different feature gate in Rust 1.83 nightly. We do not need receivers on raw pointers so this change would not affect us and usage of `arbitrary_self_types` feature would work for all Rust versions that we support (>=1.78). Cc: Adrian Taylor <ade@hohum.me.uk> Link: rust-lang/rfcs#3519 [1] Link: rust-lang/rust#44874 [2] Signed-off-by: Gary Guo <gary@garyguo.net> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240915132734.1653004-1-gary@garyguo.net Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
…ratt,wesleywiser Rename Receiver -> LegacyReceiver As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? `@wesleywiser`
…esleywiser Rename Receiver -> LegacyReceiver As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? `@wesleywiser`
Rollup merge of rust-lang#130225 - adetaylor:rename-old-receiver, r=wesleywiser Rename Receiver -> LegacyReceiver As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? `@wesleywiser`
The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in rust-lang#129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc<Self> and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
This commit contains a new Receiver trait, which is the basis for the Arbitrary Self Types v2 RFC. This allows smart pointers to be method receivers even if they're not Deref. This is currently unused by the compiler - a subsequent PR will start to use this for method resolution if the arbitrary_self_types feature gate is enabled. This is being landed first simply to make review simpler: if people feel this should all be in an atomic PR let me know. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
This commit contains a new Receiver trait, which is the basis for the Arbitrary Self Types v2 RFC. This allows smart pointers to be method receivers even if they're not Deref. This is currently unused by the compiler - a subsequent PR will start to use this for method resolution if the arbitrary_self_types feature gate is enabled. This is being landed first simply to make review simpler: if people feel this should all be in an atomic PR let me know. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
This commit contains a new Receiver trait, which is the basis for the Arbitrary Self Types v2 RFC. This allows smart pointers to be method receivers even if they're not Deref. This is currently unused by the compiler - a subsequent PR will start to use this for method resolution if the arbitrary_self_types feature gate is enabled. This is being landed first simply to make review simpler: if people feel this should all be in an atomic PR let me know. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in rust-lang#129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc<Self> and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
This commit contains a new Receiver trait, which is the basis for the Arbitrary Self Types v2 RFC. This allows smart pointers to be method receivers even if they're not Deref. This is currently unused by the compiler - a subsequent PR will start to use this for method resolution if the arbitrary_self_types feature gate is enabled. This is being landed first simply to make review simpler: if people feel this should all be in an atomic PR let me know. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
…ck-generics, r=wesleywiser Reject generic self types. The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in rust-lang#129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc<Self> and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? `@wesleywiser`
Rollup merge of rust-lang#130098 - adetaylor:arbitrary-self-types-block-generics, r=wesleywiser Reject generic self types. The RFC for arbitrary self types v2 declares that we should reject "generic" self types. This commit does so. The definition of "generic" was unclear in the RFC, but has been explored in rust-lang#129147 and the conclusion is that "generic" means any `self` type which is a type parameter defined on the method itself, or references to such a type. This approach was chosen because other definitions of "generic" don't work. Specifically, * we can't filter out generic type _arguments_, because that would filter out Rc<Self> and all the other types of smart pointer we want to support; * we can't filter out all type params, because Self itself is a type param, and because existing Rust code depends on other type params declared on the type (as opposed to the method). This PR decides to make a new error code for this case, instead of reusing the existing E0307 error. This makes the code a bit more complex, but it seems we have an opportunity to provide specific diagnostics for this case so we should do so. This PR filters out generic self types whether or not the 'arbitrary self types' feature is enabled. However, it's believed that it can't have any effect on code which uses stable Rust, since there are no stable traits which can be used to indicate a valid generic receiver type, and thus it would have been impossible to write code which could trigger this new error case. It is however possible that this could break existing code which uses either of the unstable `arbitrary_self_types` or `receiver_trait` features. This breakage is intentional; as we move arbitrary self types towards stabilization we don't want to continue to support generic such types. This PR adds lots of extra tests to arbitrary-self-from-method-substs. Most of these are ways to trigger a "type mismatch" error which https://github.com/rust-lang/rust/blob/9b82580c7347f800c2550e6719e4218a60a80b28/compiler/rustc_hir_typeck/src/method/confirm.rs#L519 hopes can be minimized by filtering out generics in this way. We remove a FIXME from confirm.rs suggesting that we make this change. It's still possible to cause type mismatch errors, and a subsequent PR may be able to improve diagnostics in this area, but it's harder to cause these errors without contrived uses of the turbofish. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? `@wesleywiser`
As part of the "arbitrary self types v2" project, we are going to replace the current `Receiver` trait with a new mechanism based on a new, different `Receiver` trait. This PR renames the old trait to get it out the way. Naming is hard. Options considered included: * HardCodedReceiver (because it should only be used for things in the standard library, and hence is sort-of hard coded) * LegacyReceiver * TargetLessReceiver * OldReceiver These are all bad names, but fortunately this will be temporary. Assuming the new mechanism proceeds to stabilization as intended, the legacy trait will be removed altogether. Although we expect this trait to be used only in the standard library, we suspect it may be in use elsehwere, so we're landing this change separately to identify any surprising breakages. It's known that this trait is used within the Rust for Linux project; a patch is in progress to remove their dependency. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang/rust#44874 r? @wesleywiser
This commit contains a new Receiver trait, which is the basis for the Arbitrary Self Types v2 RFC. This allows smart pointers to be method receivers even if they're not Deref. This is currently unused by the compiler - a subsequent PR will start to use this for method resolution if the arbitrary_self_types feature gate is enabled. This is being landed first simply to make review simpler: if people feel this should all be in an atomic PR let me know. This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 r? @wesleywiser
This PR suggests small changes to the existing unstable "aribtrary self types" feature to make it more flexible. In particular, it suggests driving this feature from a new (ish)
Receiver
trait instead of fromDeref
, but to maintain compatibility by having a blanket implementation for allDeref
types.This is a squashed commit of many edits by various folks including @Urhengulas, @Veykril , @madsmtm and myself. Thanks also to @davidhewitt, @Manishearth and many folks over on Zulip for feedback.
Rendered
Tracking issue:
arbitrary_self_types
rust#44874