]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile/internal/types2: cleanups around receiver type checks
authorRobert Griesemer <gri@golang.org>
Sat, 10 Jul 2021 04:18:12 +0000 (21:18 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 14 Jul 2021 23:33:48 +0000 (23:33 +0000)
Generic receiver types may be defined such that an instantiated
receiver ends up being a pointer type. Disallow them as we do
for non-generic receivers.

Change-Id: I6612a52615a2999375c35aa1d69ab42f37d9f55d
Reviewed-on: https://go-review.googlesource.com/c/go/+/333770
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/signature.go
src/cmd/compile/internal/types2/testdata/examples/methods.go2

index ab9a1c487ebe926efae6026f6a04a095608b629f..fa5c3f7a9b8e399898cc6cc7b6fdbe4aa8e78a55 100644 (file)
@@ -211,9 +211,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
 
                // spec: "The receiver type must be of the form T or *T where T is a type name."
                // (ignore invalid types - error was reported before)
-               if t := rtyp; t != Typ[Invalid] {
+               if rtyp != Typ[Invalid] {
                        var err string
-                       if T := asNamed(t); T != nil {
+                       switch T := rtyp.(type) {
+                       case *Named:
                                // spec: "The type denoted by T is called the receiver base type; it must not
                                // be a pointer or interface type and it must be declared in the same package
                                // as the method."
@@ -224,23 +225,30 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
                                                err = ""
                                        }
                                } else {
-                                       switch u := optype(T).(type) {
-                                       case *Basic:
-                                               // unsafe.Pointer is treated like a regular pointer
-                                               if u.kind == UnsafePointer {
-                                                       err = "unsafe.Pointer"
+                                       // The underlying type of a receiver base type can be a type parameter;
+                                       // e.g. for methods with a generic receiver T[P] with type T[P any] P.
+                                       underIs(T, func(u Type) bool {
+                                               switch u := u.(type) {
+                                               case *Basic:
+                                                       // unsafe.Pointer is treated like a regular pointer
+                                                       if u.kind == UnsafePointer {
+                                                               err = "unsafe.Pointer"
+                                                               return false
+                                                       }
+                                               case *Pointer, *Interface:
+                                                       err = "pointer or interface type"
+                                                       return false
                                                }
-                                       case *Pointer, *Interface:
-                                               err = "pointer or interface type"
-                                       }
+                                               return true
+                                       })
                                }
-                       } else if T := asBasic(t); T != nil {
+                       case *Basic:
                                err = "basic or unnamed type"
                                if check.conf.CompilerErrorMessages {
                                        check.errorf(recv.pos, "cannot define new methods on non-local type %s", recv.typ)
                                        err = ""
                                }
-                       } else {
+                       default:
                                check.errorf(recv.pos, "invalid receiver type %s", recv.typ)
                        }
                        if err != "" {
index 76c6539e1b7e7de019b7031025274eee082be8d7..4e87041e54771391056937e8b8e5424df025f5c5 100644 (file)
@@ -6,6 +6,8 @@
 
 package p
 
+import "unsafe"
+
 // Parameterized types may have methods.
 type T1[A any] struct{ a A }
 
@@ -94,3 +96,18 @@ func (_ T2[_, _, _]) _() int { return 42 }
 type T0 struct{}
 func (T0) _() {}
 func (T1[A]) _() {}
+
+// A generic receiver type may constrain its type parameter such
+// that it must be a pointer type. Such receiver types are not
+// permitted.
+type T3a[P interface{ ~int | ~string | ~float64 }] P
+
+func (T3a[_]) m() {} // this is ok
+
+type T3b[P interface{ ~unsafe.Pointer }] P
+
+func (T3b /* ERROR invalid receiver */ [_]) m() {}
+
+type T3c[P interface{ *int | *string }] P
+
+func (T3c /* ERROR invalid receiver */ [_]) m() {}