-
Notifications
You must be signed in to change notification settings - Fork 12.1k
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
Tracking issue for RFC 3519: arbitrary_self_types
#44874
Comments
Why would you need this?
I'd rather define the trait different. Maybe like this:
In this case, Rc would be a trait type. If every generic type implemented a specific trait (this could be implemented automatically for generic types) this seems more understandable to me. |
This could only be allowed for For inherent methods, I can't |
This is still pending lang team decisions (I hope there will be at least 1 RFC) but I think it will only be allowed for trait method impls. |
You can't implement anything for |
So changes needed:
|
I’ll look into this. |
Note that this is only supported to work with trait methods (and trait impl methods), aka trait Foo {
fn foo(self: Rc<Self>);
}
impl Foo for () {
fn foo(self: Rc<Self>) {}
} and is NOT supposed to work for inherent impl methods: struct Foo;
impl Foo {
fn foo(self: Rc<Self>) {}
} |
I got caught in some more Stylo work that's gonna take a while, so if someone else wants to work on this in the meantime feel free. |
Is this supposed to allow any type as long as it involves trait MyStuff {
fn a(self: Option<Self>);
fn b(self: Result<Self, Self>);
fn c(self: (Self, Self, Self));
fn d(self: Box<Box<Self>>);
}
impl MyStuff for i32 {
...
}
Some(1).a(); // ok?
Ok(2).b(); // ok?
(3, 4, 5).c(); // ok?
(box box 6).d(); // ok? |
…ents, r=nikomatsakis Update comments referring to old check_method_self_type I was browsing the code base, trying to figure out how rust-lang#44874 could be implemented, and noticed some comments that were out of date and a bit misleading (`check_method_self_type` has since been renamed to `check_method_receiver`). Thought it would be an easy first contribution to Rust!
I've started working on this issue. You can see my progress on this branch |
@arielb1 You seem adamant that this should only be allowed for traits and not structs. Aside from method shadowing, are there other concerns? |
inherent impl methods are loaded based on the type. You shouldn't be able to add a method to |
That's it, if you write something like trait Foo {
fn bar(self: Rc<Self>);
} Then it can only be used if the trait If you write an inherent impl, then it can be called without having the trait in-scope, which means we have to be more careful to not allow these sorts of things. |
@arielb1 Can you give an example of what we want to avoid? I'm afraid I don't really see what the issue is. A method you define to take |
I've been trying to figure out how we can support dynamic dispatch with arbitrary self types. Basically we need a way to take a (1) is pretty straightforward: call The tough question is, how do we get the type @arielb1 @nikomatsakis any thoughts? |
Wait, why do you not want it work for inherent impl methods? Because of scoping? I'm confused. =) |
I do want to support that, but I expected it to be out of scope for this first cut. That is, I expected that if a trait uses anything other than |
I know, but I couldn't help looking into it, it's all very interesting to me :) |
We need some sort of "orphan rule" to at least prevent people from doing things like this: struct Foo;
impl Foo {
fn frobnicate<T>(self: Vec<T>, x: Self) { /* ... */ }
} Because then every crate in the world can call Maybe the best way to solve this would be to require I think that if we have the deref-back requirement, there's no problem with allowing inherent methods - we just need to change inherent method search a bit to also look at defids of derefs. So that's probably a better idea than restricting to trait methods only. Note that the struct Foo;
impl Tr for Foo {
fn frobnicate<A: Allocator+?Sized>(self: RcWithAllocator<Self, A>) { /* ... */ }
} Where an |
Are saying is that there would be a "conflicting symbols for architechture x86_64..." linker error?
I'm confused, are you still talking about |
The deref-back requirement is supposed to be for everything, not only object-safety. It prevents the problem when one person does struct MyType;
impl MyType {
fn foo<T>(self: Vec<(MyType, T)>) { /* ... */ }
} While another person does struct OurType;
impl OurType {
fn foo<T>(self: Vec<(T, OurType)>) {/* ... */ }
} And now you have a conflict on |
Hey @adetaylor, I'm sorry I didn't really understand what you wrote above, I'm not well-enough versed in What I wanted to discuss was basically that, if we stabilize struct MyBox<T>(T);
impl<T> Deref<Target = T> for MyBox<T> { ... }
impl<T> DerefMut for MyBox<T> { ... }
unsafe impl<T> MethodReceiver for MyBox<T> { ... } I would expect it be a compile-error, because Maybe, as a library implementer, I'm just confused about your proposal for // Crate foo
pub struct FooPtr<T>(NonNull<T>);
unsafe impl<T> MethodReceiver for FooPtr<T> {}
// Does not implement `Deref` and `DerefMut`, since that is undesired for this type
// Crate bar
struct Bar;
impl Bar {
// Now possible, because of the `MethodReceiver` implementation.
fn method(self: FooPtr<Self>) { ... }
} Is it just because the other definition would allow handling |
Without the However, I'm not sure what the purpose of the Additionally, why restrict the number of // Assuming these:
impl<T: ?Sized> MethodReceiver for Cell<T> { type Target = T; }
impl<T: ?Sized> MethodReceiver for *const T { type Target = T; }
// One should be able to write:
struct Foo;
impl Foo {
fn weird(self: *const Cell<Self>) { ... }
} |
AIUI, the pointer from the trait MyTrait {
fn foo(self: Rc<Self>);
}
impl MyTrait for () {
fn foo(self: Rc<Self>) { ... }
}
let bar: Rc<dyn MyTrait> = Rc::new(());
bar.foo(); // we need to find method at runtime via the vtable |
Isn't that handled by the |
Hi @madsmtm ,
You're assuming a blanket implementation of |
This way both |
I'd like to mention this issue here. #![feature(arbitrary_self_types)]
use std::ops::Deref;
struct Foo(u32);
impl Foo {
fn get<R: Deref<Target=Self>>(self: R) -> u32 {
self.0
}
}
fn main() {
let mut foo = Foo(1);
foo.get::<&Foo>(); // Error
} The issue being that the self parameter is generic, however, in the call the turbofish operator is used to specify which exact argument type is being used. |
@adetaylor I just wanted to say thank you for exploring an RFC for this, arbitrary self types provide an elegant solution for the main challenge I would like to resolve before a PyO3 1.0 (i.e. the Python interop you note above). If there's anything I can do to help you, please ping me! |
Thanks also to @Urhengulas and @amanjeev who are working on it too! |
This issue has become impossible to follow (150 comments, most of them hidden by github). Tracking issues in general have a tendency to become unmanageable. Please open a dedicated new issue and label it with
F-arbitrary_self_types
|
arbitrary_self_types
arbitrary_self_types
For all those following this tracking issue, note that RFC 3519 ("Arbitrary self types v2") has been accepted and merged: We'll continue to use this issue to track the progress toward this second version of arbitrary self types. Thanks to @adetaylor for pushing forward on this important work. |
Here's how I plan to approach actually implementing this. For the immediate future, I'll be working in this branch, rebasing and rewriting history frequently. Bits of that branch will occasionally migrate to PRs which I try to land. The tricky bit about landing this work is that there are already a cluster of feature gates involved, and we need to adjust them towards this agreed end-state incrementally. I think the phasing of PRs has to be something like this:
Help with any of these stages is very much appreciated - as is any wisdom about whether there's a better order to do things, or whether things should be split up into more or fewer PRs - it's my first major Rust change. |
This is the tracking issue for RFC 3519: Arbitrary self types v2.
The feature gate for this issue is
#![feature(arbitrary_self_types)]
.About tracking issues
Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.
Steps
Unresolved Questions
None.
Related
Implementation history
TODO.
(Below follows content that predated the accepted Arbitrary Self Types v2 RFC.)
Object Safety
See #27941 (comment)
Handling of inference variables
Calling a method on
*const _
could now pick impls of the formBecause method dispatch wants to be "limited", this won't really work, and as with the existing situation on
&_
we should be emitting an "the type of this value must be known in this context" error.This feels like fairly standard inference breakage, but we need to check the impact of this before proceeding.
Safe virtual raw pointer methods
e.g. this is UB, so we might want to force the call
<dyn Foo as Foo>::bar
to be unsafe somehow - e.g. by not allowingdyn Foo
to be object safe unlessbar
was anunsafe fn
However, even today you could UB in safe code with
mem::size_of_val(foo)
on the above code, so this might not be actually a problem.More information
There's no reason the
self
syntax has to be restricted to&T
,&mut T
andBox<T>
, we should allow for more types there, e.g.The text was updated successfully, but these errors were encountered: