]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] go/types: cleanups around receiver type checks
authorRob Findley <rfindley@google.com>
Sat, 17 Jul 2021 00:40:58 +0000 (20:40 -0400)
committerRobert Findley <rfindley@google.com>
Mon, 19 Jul 2021 17:09:14 +0000 (17:09 +0000)
This is a port of CL 333770 to go/types, adjusted for the error
reporting API and to not support compiler error messages. An error
message changed (to 'invalid receiver type' from just 'invalid
receiver'), so a test had to be adjusted.

Change-Id: I166e8831d8c9f98ebfb0270fe5221586fc112825
Reviewed-on: https://go-review.googlesource.com/c/go/+/335079
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/signature.go
src/go/types/testdata/examples/methods.go2
src/go/types/testdata/fixedbugs/issue28251.src

index 85a735120f42c70dc713256a081c46e5657b533b..da01ec801a5a6afa893c12469a3b2f76da2ba1cb 100644 (file)
@@ -199,30 +199,40 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
 
                // 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."
                                if T.obj.pkg != check.pkg {
                                        err = "type not defined in this package"
                                } 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 {
+                       case *Basic:
                                err = "basic or unnamed type"
+                       default:
+                               check.errorf(recv, _InvalidRecv, "invalid receiver type %s", recv.typ)
                        }
                        if err != "" {
-                               check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err)
+                               check.errorf(recv, _InvalidRecv, "invalid receiver type %s (%s)", recv.typ, err)
                                // ok to continue
                        }
                }
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() {}
index cd79e0e8b5d299e905628654369e8df0db5477fe..ef5e61df47f2c5e332a5db29e82f24bccadbd5e0 100644 (file)
@@ -60,6 +60,6 @@ type (
         T11 = T
 )
 
-func (T9 /* ERROR invalid receiver \*\*T */ ) m9() {}
+func (T9 /* ERROR invalid receiver type \*\*T */ ) m9() {}
 func _() { (T{}).m9 /* ERROR has no field or method m9 */ () }
 func _() { (&T{}).m9 /* ERROR has no field or method m9 */ () }