-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Decide about generics in arbitrary self types #129147
Comments
Thanks for raising this @traviscross . |
Current status: investigating whether I can improve the diagnostics here that can occur when generics are used and the self type doesn't unify cleanly. The canonical failure case is here and the suggestion to improve diagnostics here is from this comment by @compiler-errors. Outcomes might be:
Once I've got to the bottom of this, I'll report back, with some thoughts on all the reasons we might have wanted to exclude generics (not just diagnostics). |
Adding tests for cases where diagnostics aren't as good as they should be in the case of arbitrary self types. These are slightly duplicative of the existing arbitrary-self-from-method-substs.rs test, but test more permutations so it seems worth adding to the coverage as we explore improving the diagnostics here. Improved diagnostics were suggested in commit 05c5caa This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 and specifically the sub-issue exploring questions around generics, rust-lang#129147
Adding tests for cases where diagnostics aren't as good as they should be in the case of arbitrary self types. These are slightly duplicative of the existing arbitrary-self-from-method-substs.rs test, but test more permutations so it seems worth adding to the coverage as we explore improving the diagnostics here. Restritions here were suggested in commit 05c5caa This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 and specifically the sub-issue exploring questions around generics, rust-lang#129147
Adding tests for cases where diagnostics aren't as good as they should be in the case of arbitrary self types. These are slightly duplicative of the existing arbitrary-self-from-method-substs.rs test, but test more permutations so it seems worth adding to the coverage as we explore improving the diagnostics here. Restritions here were suggested in commit 05c5caa This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 and specifically the sub-issue exploring questions around generics, rust-lang#129147
Adding tests for cases where diagnostics aren't as good as they should be in the case of arbitrary self types. These are slightly duplicative of the existing arbitrary-self-from-method-substs.rs test, but test more permutations so it seems worth adding to the coverage as we explore improving the diagnostics here. Restritions here were suggested in commit 05c5caa This is a part of the arbitrary self types v2 project, rust-lang/rfcs#3519 rust-lang#44874 and specifically the sub-issue exploring questions around generics, rust-lang#129147
Here's a summary of the concerns and considerations about why we might want to block generic arbitrary self Also, I finally found the original suggestion to ban generics from @RalfJung , which led to the commit editing the RFC to do so.
IMO the only remaining reason to avoid generic receiver types is the desire to avoid "unknown unknowns" per this third point. This is a good reason, but there are counterarguments:
As such: I am now firmly of the opinion that we should just allow generic receivers, as the current nightly arbitrary self types v1 does. |
Thank you for the detailed and thorough analysis! If @RalfJung is on board with this analysis, then 👍 for lifting the restriction on generics. |
I just suggested that we should be conservative here. My gut feeling is that we should "know the receiver type constructor" (i.e., identify the relevant I'm too out of the loop to follow the details of the suggestion here, this sounds like a question for @rust-lang/types. :) |
I don't see any reason why we should need to support generics that come from the method itself. That should be easy enough to detect. |
OK, to check I understand your proposal, we want to distinguish these cases: struct MyBox<T>(T);
impl<T> Receiver for MyBox<T> {
type Target = T;
}
struct Foo;
impl Foo {
fn ok(self: MyBox<Foo>) {}
fn not_ok1<X: Receiver<Target=Self>>(self: X) {}
fn not_ok2<A: Allocator>(self: Box<Self, A>)) {}
} To detect this I'm assuming we want to do something along these lines in
The new diagnostic might be something like:
(We can probably optimize to avoid two separate validation passes, but semantically, that's what you think we should aim for?) I'm a bit concerned about the |
I would imagine that has an impl like It is only when using a |
After looking at the options, I agree with @compiler-errors 's plan here. Specifically, we'll reject methods where the outermost receiver type is:
All other self types pass the test, including types which refer to such type params in their generic arguments. This filter seems to work as desired - I'm working on a PR now. RationaleDocumenting the thought process here for posterity. First,
I'm worried about explicitly filtering out I had a various chats with @Darksonn about this this weekend (thanks!) She made me realize that the only thing which matters is the outermost type kind, not any generic parameters elsewhere in the type. I think that's what the rest of you have been telling me for days too but I hadn't figured that out :) We discussed only allowing concrete paths as the outermost type. I think the fundamentals of that idea are sound, but it turns out to be a bit more complex:
The key case turns out to be our old friend, // Both Self and A below are ty::Param
pub trait Future {
fn poll(self: Pin<&mut Self>) {} // must compile
}
pub trait Foo {
fn poll<A: Deref<Target=Self>>(self: Pin<&mut A>) {} // probably should NOT compile
} So, IMO this proves that the "good vs bad" filter must involve distinguishing some The Hence - I'm now pretty sure that this is the right plan. If that doesn't make any sense, don't worry - PR coming along soon which will make it clearer. |
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
I'm not sure this quite aligns with my intuotion... If the receiver type is "&MyType<T>” and we also have a "where MyType<T>: Receiver", this is still just as generic as the cases we want to rule out, isn't it?
The key distinction is really whether we can prove that this is a receiver type without using the where clauses.
|
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
I've attempted to come up with an alternative PR which rejects all
The second approach should reject methods whose However, this second approach doesn't currently work due to the impl<T> Node<T> {
fn into_element<A: Allocator>(self: Box<Self, A>) -> T {
self.element
}
} and this in impl<T> [T] {
pub fn into_vec<A: Allocator>(self: Box<Self, A>) -> Vec<T, A> {
// ...
}
} Presumably we'd find similar patterns in third party crates too. So... we can't just entirely ignore the type params belonging to the method. It's very hard to think of a compromise here. Even if I could figure out a way to retain the type params but not their predicates, that won't help, because we need the Thanks to @nbdd0121 and (again) @Darksonn for help here. I think the options are:
|
I feel the allocator bound is a legit use of arbitrary self types and therefore ignoring predicates on impl item would not be a good approach. We could filter out only predicates that mention Deref/DerefMut, but it feels pretty ad-hoc and people can workaround by defining a new trait with Deref being it's super trait, so that's probably also not a good approach. I would suggest that we drop the non-generic requirement all-together. |
No, as there we have a single |
I've suggested a compromise multiple times: we have to be able to identify the unique I don't know how to implement that, as I know nothing about the trait solver, but as far as I can see this is entirely well-defined. |
I don't think that'll work, since for the |
Ah, that's how these two traits interact? I was wondering about that. Yeah okay if we have such generic Anyway, if t-types says there is no problem here then that's fine for me as well. |
I suppose we can first resolve |
so something like https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=feca59e56ec2092732906a7c10493f67? |
Yeah, something like that. Those impls can now have completely different I am surprised that this even compiles... are we considering every inherent method of every type to be a potential candidate here to find out which one gets called? Won't that be a mess? |
we do the following:
We only look at the inherent methods of types discovered as part of the |
Ah, that is the pat I was missing in my mental model. Thanks! |
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
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
…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`
Over here, @adetaylor gave an update about arbitrary self types that included this bit:
We never made a decision about this. Perhaps if we could offer more clarity, it would save @adetaylor some time here, so it may be worth us discussing.
@rustbot labels +T-lang +I-lang-nominated -needs-triage +C-discussion
cc @rust-lang/lang @adetaylor
The text was updated successfully, but these errors were encountered: