-
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
unsized params in traits #3745
base: master
Are you sure you want to change the base?
unsized params in traits #3745
Conversation
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.
The formatting is a bit unusual. Maybe have a look at other RFCs for inspiration.
Also there's a short motivation that is only clear if one already read the issue or a later section. I think parts of the guide explanation are actually motivation pieces
# Summary | ||
[summary]: #summary | ||
|
||
A (temporary) lint which detects unsized parameter in required trait methods, which will become a hard |
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 call these future incompatibility lints https://rustc-dev-guide.rust-lang.org/diagnostics.html?highlight=Futur#future-incompatible-lints
fn bar(bytes: [u8]); | ||
} | ||
``` | ||
the above code would work without the lint (how did no one notice this?) |
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.
That kind of question doesn't belong in the RFC text
|
||
this feature will be very simple to implement (i hope), just port the `Sized`-checking logic from provided methods to required methods, if that is possible (also maybe from regular functions) and throw an error/warning/nothing depending on the lint level. | ||
|
||
here is some rust-pseudo code: |
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.
This kind of detail is not necessary.
# ... | ||
``` | ||
|
||
# Rationale and alternatives |
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.
An alternative could be to generate where Self: Sized
bounds from the signature where applicable and thus never actually forbid 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.
This is what the Reference (inaccurately) says currently happens, for context.
source
https://doc.rust-lang.org/reference/items/traits.html#object-safety
[...] A trait is object safe if it has the following qualities [...] All associated functions must either be dispatchable from a trait object or be explicitly non-dispatchable: [...] Dispatchable functions must: [...] Not have a where Self: Sized bound (receiver type of Self (i.e. self) implies this). [...] Explicitly non-dispatchable functions require: Have a where Self: Sized bound (receiver type of Self (i.e. self) implies this).
(emphasis mine)
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.
This would, for the record, break the dyn compatibility of FnOnce
.
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.
So does this RFC. And we'd have to revert this RFC whenever we figure out generally allowing folk to call owned methods on Box<dyn TheirTrait>
For example: C++ does not really have unsized types (that i know of) | ||
Another: C# abstracts the idea of a `Sized` value | ||
|
||
Higher level languages do not need to run on the machine directly so there is no need to know the size of a value |
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.
These examples are the opposite of prior art. They explain where there's no prior art. Maybe you can find similar requirements in Rust? I think function pointers are similarly definable with arguments that no real function can have
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.
The trivial bounds feature has similar situations, too
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Hey everyone im going to make another RFC for this |
Obviously the above code isnt actually correct as it doesnt check _which_ param is unsized, it just checks if there is, (you can probably loop over the 'filter' object, and make an individual error for each one) | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks |
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.
One drawback is that it causes a lot of churn. The RFC should have a rationale for what the advantage is of adding a Self: Sized
bound to e.g. IntoIterator::into_iter
or Add:add
.
I personally find the argument "why allow Thinking about this (and from a short private chat about this), there are some significant issues here
I feel that especially the existence of @ionicmc-rs Please do not open a separate RFC here but instead update this RFC in place if necessary. Also, it may be good to take the RFC a bit slower and first participate in some less formal discussion to save yourself unnecessary work. |
Ok wait let me try that |
It is now updated, closing the new PR |
But it is marked as internal though, why? |
rust-lang/rust#126830 based on reasoning from rust-lang/rust#123894 (comment). My perspective is that the current impl is simply known to be insufficient, but something like it remains necessary and imo expected to get stabilized at some point |
Hmm... So this just stays as a lint? |
Even as a lint this is highly undesirable if there'll ever be a future where // Imagine this trait, if we'd lint on this there would be 2 possible solutions
trait Trait {
fn foo(self);
}
// Add a `Sized` bound to the trait
trait SizedAsSuper: Sized {
fn foo(self);
}
// Add a `Sized` bound to the method
trait SizedOnMethod {
fn foo(self)
where
Self: Sized;
} Note how in these cases the Now, while this is already an issue as it means you'd have to wait for the trait definitions in your dependencies to be updated before being able to use a new feature, the dependencies can also not be updated without a breaking change. trait RelyOnSuper: SizedAsSuper {
fn needs_sized() -> [Self; 8];
}
trait RelyOnSuperErr: Trait {
fn needs_sized() -> [Self; 8]; // ERROR: `Self: Sized` is not known to hold
} Right now I don't think adding a where-bound to the method can be exploited, but I do expect 2 potential ways in which it will be in the future // We probably want to allow impls for unsized types
// to not define methods with trivially unsatisfiable bounds.
//
// Especially as otherwise adding `Self: Sized` as a method where-bound
// doesn't actually help with the issue of "this trait is accidentally not
// implementable for unsized types"
trait RelyOnMethodBound {}
impl SizedOnMethod for dyn RelyOnMethodBound {}
// Removing the `Self: Sized` bounds would then make this an error
impl Trait for dyn RelyOnMethodBound {} alternatively, once we stabilize // The `Self: Sized` bound is only allowed because it's
// implied by the trait definition.
trait RelyOnMethodBound {}
impl SizedOnMethod for dyn RelyOnMethodBound {
fn foo(self)
where
Self: Sized
{}
} |
Well this issue needs to be addressed in some way, even if not like this |
link doesn't work |
why? we can keep this somewhat suboptimal status quo which will end up being perfectly fine once |
Well I guess, but that feature needs to be stabalized before this issue is addressed, which is suboptimal but I guess it's ok |
so... there are multiple moderately related issues at hand (mostly repeating what lcnr said in a different order):
trait Foo {
fn foo(self);
}
impl Foo for str {
fn foo(self) {} // Error (for now, until we get unsized locals)
}
trait Foo {
fn foo(self) where Self: Sized;
}
impl Foo for str {} // Error: not all members implemented Well you can, but only with #![feature(trivial_bounds)]
trait Foo {
fn foo(self) where Self: Sized;
}
impl Foo for str {
fn foo(self) where Self: Sized {}
//^ Uncallable function, but compiles
}
trait Foo {
fn foo(self);
}
fn bar(_: &dyn Foo) {} // Error: not dyn safe I think we can do something about point trait Foo {
fn foo(self) where Self: Sized;
}
fn bar(_: &dyn Foo) {} // ok! works just fine, because all methods with So we could just allow trait Foo {
fn foo(self) where Self: Sized;
}
impl Foo for str {} in the same way. Unfortunately, as lcnr already mentioned, we cannot just make trait Foo {
fn foo(self);
}
impl Foo for str {} work, as with the unsized_fn_params feature it will be just fine: #![feature(unsized_fn_params)]
trait Foo {
fn foo(self);
}
impl Foo for str {
fn foo(self) {} // works
} so... The only thing this RFC would achieve is to push authors of crates with public trait declarations to make them add My conclusion thus is still to close the RFC, and just implement allowing trait Foo {
fn foo(self) where Self: Sized;
}
impl Foo for str {} with a simple FCP on the PR adding it, similar to what I did in rust-lang/rust#112319 I tried to do this a while back (rust-lang/rust#112929), so it isn't trivial, but we can probably do a simple version just for |
There's no error here; |
issue for this RFC rust-lang/rust#134475
This RFC proposes checking for
T: Sized
in required trait methods (which do not check for some reason) which will be a future compatibility lintRendered