-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
go/types, cmd/compile/internal/types2: disallow type parameters as RHS of type declarations #45639
Comments
Change https://golang.org/cl/311455 mentions this issue: |
Our proposals do not explain what |
Yes, sorry to be clear the problem here may only be the misleading error message. I wasn't sure. I think we should either allow Y to have a type parameter as its underlying type (and remove the guard against type parameters in Perhaps in the absence of any reason to write this code, we should err on the side of caution and disallow such a declaration (at least for now). |
Let's disallow it for now. Same for local aliases of type parameters (even though those shouldn't be a problem, I think). |
Sounds good. Updated the issue accordingly. |
Add handling for TypeParams in NewMethodSet, to bring it in sync with lookupFieldOrMethod. Also add a test, since we had none. I wanted this fix to get gopls completion working with type params, but due to the subtlety of lookupFieldOrMethod, I left a TODO to confirm that there are no behavioral differences between the APIs. Updates #45639 Change-Id: I16723e16d4d944ca4ecb4d87fc196815abb6fcff Reviewed-on: https://go-review.googlesource.com/c/go/+/311455 Trust: Robert Findley <rfindley@google.com> Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
As discussed in #43621, the case of |
Per discussion with @iant, we do want to permit (non-local) generic type declarations of the form type T[P C] P because those are useful, for instance to add methods to a type P. But we don't want to permit (local) type declarations of the form type T P where |
Change https://golang.org/cl/332411 mentions this issue: |
…rameter as RHS of a type declaration For #45639. Change-Id: I20e331b04f464db81e916af75f70ec8ae73eb989 Reviewed-on: https://go-review.googlesource.com/c/go/+/332411 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
As noted at #43621 (comment), it's not safe/possible to add methods to pointer or interface types. So What are some of the examples of where this is useful? Would they not be equally useful/applicable if |
/cc @ianlancetaylor (apologies to @ iant) |
At top level defining a type as its own parameter is useful as seen, for example, in the code (still using old syntax) at https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#absolute-difference . |
Thanks. It seems like the consequence of disallowing
needs to be written instead as:
That doesn't seem substantively different to me. I'm still currently leaning for blanket disallowing |
I don't feel strongly about it. |
On CL 294469, @ianlancetaylor wrote:
My point is if you instantiate I think a reasonable rule could be something like "it's invalid to embed a type into a struct if its method set depends upon the type arguments used for instantiation," but that's fairly subtle both to specify and implement. I'd rather defer to post-1.18 to worry about specifying a rule like that, assuming there's user demand. |
I'm not quite following you, sorry. My way of thinking is that compile-time and execution-time handling of type parameters are two different things. At compile time we have various complexities where we are trying to work through exactly which type arguments are permitted and exactly which operations are permitted on those type arguments. I don't think we're there yet when it comes to things like promoted methods. At execution time, though, we know what we want: the function should act as though the type parameters are consistently replaced throughout by the type arguments. We know here are some cases there where we have to be different, as in With this view, I'm not sure where confusion about method promotion arises. I'm not saying that it doesn't arise, I just don't see it yet. It's worth noting that it may be the case that some code is too complicated for dictionaries. For some code we may have to fall back to stenciling. I think that's fine, assuming that that code is not common. It's also of course fine to postpone handling some cases entirely. But I don't know why we would want a rule like "it's invalid to embed a type into a struct if its method set depends upon the type arguments used for instantiation." Maybe we do. And it's quite possible that we want a compile-time rule like "if the method set of an embedded type depends on type arguments, then those methods may not be called." But I'm not sure why we need a rule like this at execution time. |
I'm reopening this issue for more consideration for the 1.19 release. There won't be any further change for 1.18. The specific question is whether to permit type P[T C] T and then permit defining methods on |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I arrived at this issue trying the following: package main
import (
"bytes"
"io"
)
func main() {
Show(bytes.NewBufferString(""))
}
type Body[T any] = T
func Show(body Body[io.Reader]) {
buf, err := ioutil.ReadAll(body)
} And getting this error:
I thought I'd share my use case for wanting alias support, though I admit, it might be rather niche. I'd like to (ab)use the |
Here is an implementation of absolute difference from the Type Parameters Proposal that does not use type parameters as RHS of type: The code does not compile:
|
…nstraints package existing now
Here's a type of case I've run into that would clearly benefit from allowing declarations of What I want to do is: type VarLenBits interface {
~[1]uint64 | ~[2]uint64 | ~[3]uint64 | ~[4]uint64 | ~[]uint64
}
// ERROR: cannot use a type parameter as RHS in type declaration
type bitVectorV[T VarLenBits] T
// This doesn't work because of invalid type bitVectorV:
func (b bitVectorV[T]) hammingD(a bitVectorV[T]) (d int) {
for i := 0; i < len(a); i++ {
d += bits.OnesCount64(a[i] ^ b[i])
}
return d
} Nope... How about make it a pointer instead? // Valid!
type bitVectorP[T VarLenBits] *T
// ERROR: invalid receiver type bitVectorP[T] (pointer or interface type)
func (bp bitVectorP[T]) hammingD(ap bitVectorP[T]) (d int) {
a, b := *ap, *bp
for i := 0; i < len(a); i++ {
d += bits.OnesCount64(a[i] ^ b[i])
}
return d
} Hmmm... Maybe this will work! type bitVectorA[T VarLenBits] [1]*T
func newBVA[T bitVectorA[A], A VarLenBits](in *A) (out T) {
out[0] = in
return
}
// Works!
func (bp bitVectorA[T]) hammingD(ap bitVectorA[T]) (d int) {
a, b := *ap[0], *bp[0]
for i := 0; i < len(a); i++ {
d += bits.OnesCount64(a[i] ^ b[i])
}
return d
} The above kludge (using More elaboration of this case with working code here: https://go.dev/play/p/fl9rBkCrMNi |
This restriction (disallow type parameters as RHS of type declarations) has been implemented for 1.18. There's nothing left to do here for now. If we want to change this behavior we need a detailed proposal. Closing. |
Playing devils advocate, having the ability to do this would make it easier to marshal multiple structs into a flat namespace. Consider the following: You are writing an HTTP client library. You have methods wrapping various API endpoints, each with a struct outlining the body for the associated API. Users of your library are requesting the ability to supply additional fields for the body beyond what is explicitly defined in the struct. You have two options:
While the second approach doesn't support a custom body whose type is |
The generic Enum type didn't work, as it failed with: "cannot use a type parameter as RHS in type declaration" golang/go#45639
Consider the following snippet, with annotated type checking error.
This error is both inaccurate and (as a secondary concern) fails to mention the named type
Y
.Update: per discussion below, let's disallow such declarations (as well as
type Y = T
) for now.CC @griesemer
The text was updated successfully, but these errors were encountered: