]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: record pointer and parentheses in receiver expressions
authorRobert Griesemer <gri@golang.org>
Mon, 29 Jul 2024 22:29:08 +0000 (15:29 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 30 Jul 2024 23:42:46 +0000 (23:42 +0000)
CL 594740 rewrote type checking of method receiver types. Because that
CL takes apart receivers "manually" rather than using the regular code
for type checking type expressions, pointer and parenthesized receiver
type expressions were not recorded anymore.

Adjust the code that typechecks method receivers to a) use ordinary
type expression checking for non-generic receivers, and b) to record
a missing pointer and any intermediate parenthesized expressions in
case of a generic receiver.

Add many extra tests verifying that the correct types for parenthesized
and pointer type expressions are recorded in various source positions.

Note that the parser used by the compiler and types2 doesn't encode
unnecessary parentheses in type expressions in its syntax tree.
As a result, the tests that explicitly test parentheses don't work
in types2 and are commented out.

This CL adds code (disabled by default) to the parser to encode
parentheses in type expressions in the syntax tree. When enabled,
the commented out types2 tests pass like in go/types.

Fixes #68639.
For #51343.

Change-Id: Icf3d6c76f7540ee53e229660be8d78bb25380539
Reviewed-on: https://go-review.googlesource.com/c/go/+/601657
Reviewed-by: Tim King <taking@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/signature.go
src/go/types/api_test.go
src/go/types/expr.go
src/go/types/signature.go

index 66570fe92a823bb2993c4a786cca2be7cb3e97f2..20106f4e61aee0a2047ab7bdd99a47c5edf56c1d 100644 (file)
@@ -1398,6 +1398,16 @@ func (p *parser) typeOrNil() Expr {
                p.next()
                t := p.type_()
                p.want(_Rparen)
+               // The parser doesn't keep unnecessary parentheses.
+               // Set the flag below to keep them, for testing
+               // (see e.g. tests for go.dev/issue/68639).
+               const keep_parens = false
+               if keep_parens {
+                       px := new(ParenExpr)
+                       px.pos = pos
+                       px.X = t
+                       t = px
+               }
                return t
        }
 
index d73e8fa95ecf408b3eb03a1e12274d906f9ad04f..2a3c76bb885bcfdee44bc88e515ca0d43f8386f2 100644 (file)
@@ -403,6 +403,118 @@ func TestTypesInfo(t *testing.T) {
                {`package s8; func _() { f(g, h) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func(int, string)`},
                {`package s9; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func[P, Q any](P, Q)`}, // go.dev/issues/60212
                {`package s10; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h[int]`, `func(int, string)`},
+
+               // go.dev/issue/68639
+               // parenthesized and pointer type expressions in various positions
+               // (note that the syntax parser doesn't record unnecessary parentheses
+               // around types, tests that fail because of that are commented out below)
+               // - as variable type, not generic
+               {`package qa1; type T int; var x T`, `T`, `qa1.T`},
+               {`package qa2; type T int; var x (T)`, `T`, `qa2.T`},
+               // {`package qa3; type T int; var x (T)`, `(T)`, `qa3.T`}, // parser doesn't record parens
+               {`package qa4; type T int; var x ((T))`, `T`, `qa4.T`},
+               // {`package qa5; type T int; var x ((T))`, `(T)`, `qa5.T`}, // parser doesn't record parens
+               // {`package qa6; type T int; var x ((T))`, `((T))`, `qa6.T`}, // parser doesn't record parens
+               {`package qa7; type T int; var x *T`, `T`, `qa7.T`},
+               {`package qa8; type T int; var x *T`, `*T`, `*qa8.T`},
+               {`package qa9; type T int; var x (*T)`, `T`, `qa9.T`},
+               {`package qa10; type T int; var x (*T)`, `*T`, `*qa10.T`},
+               {`package qa11; type T int; var x *(T)`, `T`, `qa11.T`},
+               // {`package qa12; type T int; var x *(T)`, `(T)`, `qa12.T`}, // parser doesn't record parens
+               // {`package qa13; type T int; var x *(T)`, `*(T)`, `*qa13.T`}, // parser doesn't record parens
+               // {`package qa14; type T int; var x (*(T))`, `(T)`, `qa14.T`}, // parser doesn't record parens
+               // {`package qa15; type T int; var x (*(T))`, `*(T)`, `*qa15.T`}, // parser doesn't record parens
+               // {`package qa16; type T int; var x (*(T))`, `(*(T))`, `*qa16.T`}, // parser doesn't record parens
+
+               // - as ordinary function parameter, not generic
+               {`package qb1; type T int; func _(T)`, `T`, `qb1.T`},
+               {`package qb2; type T int; func _((T))`, `T`, `qb2.T`},
+               // {`package qb3; type T int; func _((T))`, `(T)`, `qb3.T`}, // parser doesn't record parens
+               {`package qb4; type T int; func _(((T)))`, `T`, `qb4.T`},
+               // {`package qb5; type T int; func _(((T)))`, `(T)`, `qb5.T`}, // parser doesn't record parens
+               // {`package qb6; type T int; func _(((T)))`, `((T))`, `qb6.T`}, // parser doesn't record parens
+               {`package qb7; type T int; func _(*T)`, `T`, `qb7.T`},
+               {`package qb8; type T int; func _(*T)`, `*T`, `*qb8.T`},
+               {`package qb9; type T int; func _((*T))`, `T`, `qb9.T`},
+               {`package qb10; type T int; func _((*T))`, `*T`, `*qb10.T`},
+               {`package qb11; type T int; func _(*(T))`, `T`, `qb11.T`},
+               // {`package qb12; type T int; func _(*(T))`, `(T)`, `qb12.T`}, // parser doesn't record parens
+               // {`package qb13; type T int; func _(*(T))`, `*(T)`, `*qb13.T`}, // parser doesn't record parens
+               // {`package qb14; type T int; func _((*(T)))`, `(T)`, `qb14.T`}, // parser doesn't record parens
+               // {`package qb15; type T int; func _((*(T)))`, `*(T)`, `*qb15.T`}, // parser doesn't record parens
+               // {`package qb16; type T int; func _((*(T)))`, `(*(T))`, `*qb16.T`}, // parser doesn't record parens
+
+               // - as method receiver, not generic
+               {`package qc1; type T int; func (T) _() {}`, `T`, `qc1.T`},
+               {`package qc2; type T int; func ((T)) _() {}`, `T`, `qc2.T`},
+               // {`package qc3; type T int; func ((T)) _() {}`, `(T)`, `qc3.T`}, // parser doesn't record parens
+               {`package qc4; type T int; func (((T))) _() {}`, `T`, `qc4.T`},
+               // {`package qc5; type T int; func (((T))) _() {}`, `(T)`, `qc5.T`}, // parser doesn't record parens
+               // {`package qc6; type T int; func (((T))) _() {}`, `((T))`, `qc6.T`}, // parser doesn't record parens
+               {`package qc7; type T int; func (*T) _() {}`, `T`, `qc7.T`},
+               {`package qc8; type T int; func (*T) _() {}`, `*T`, `*qc8.T`},
+               {`package qc9; type T int; func ((*T)) _() {}`, `T`, `qc9.T`},
+               {`package qc10; type T int; func ((*T)) _() {}`, `*T`, `*qc10.T`},
+               {`package qc11; type T int; func (*(T)) _() {}`, `T`, `qc11.T`},
+               // {`package qc12; type T int; func (*(T)) _() {}`, `(T)`, `qc12.T`}, // parser doesn't record parens
+               // {`package qc13; type T int; func (*(T)) _() {}`, `*(T)`, `*qc13.T`}, // parser doesn't record parens
+               // {`package qc14; type T int; func ((*(T))) _() {}`, `(T)`, `qc14.T`}, // parser doesn't record parens
+               // {`package qc15; type T int; func ((*(T))) _() {}`, `*(T)`, `*qc15.T`}, // parser doesn't record parens
+               // {`package qc16; type T int; func ((*(T))) _() {}`, `(*(T))`, `*qc16.T`}, // parser doesn't record parens
+
+               // - as variable type, generic
+               {`package qd1; type T[_ any] int; var x T[int]`, `T`, `qd1.T[_ any]`},
+               {`package qd2; type T[_ any] int; var x (T[int])`, `T[int]`, `qd2.T[int]`},
+               // {`package qd3; type T[_ any] int; var x (T[int])`, `(T[int])`, `qd3.T[int]`}, // parser doesn't record parens
+               {`package qd4; type T[_ any] int; var x ((T[int]))`, `T`, `qd4.T[_ any]`},
+               // {`package qd5; type T[_ any] int; var x ((T[int]))`, `(T[int])`, `qd5.T[int]`}, // parser doesn't record parens
+               // {`package qd6; type T[_ any] int; var x ((T[int]))`, `((T[int]))`, `qd6.T[int]`}, // parser doesn't record parens
+               {`package qd7; type T[_ any] int; var x *T[int]`, `T`, `qd7.T[_ any]`},
+               {`package qd8; type T[_ any] int; var x *T[int]`, `*T[int]`, `*qd8.T[int]`},
+               {`package qd9; type T[_ any] int; var x (*T[int])`, `T`, `qd9.T[_ any]`},
+               {`package qd10; type T[_ any] int; var x (*T[int])`, `*T[int]`, `*qd10.T[int]`},
+               {`package qd11; type T[_ any] int; var x *(T[int])`, `T[int]`, `qd11.T[int]`},
+               // {`package qd12; type T[_ any] int; var x *(T[int])`, `(T[int])`, `qd12.T[int]`}, // parser doesn't record parens
+               // {`package qd13; type T[_ any] int; var x *(T[int])`, `*(T[int])`, `*qd13.T[int]`}, // parser doesn't record parens
+               // {`package qd14; type T[_ any] int; var x (*(T[int]))`, `(T[int])`, `qd14.T[int]`}, // parser doesn't record parens
+               // {`package qd15; type T[_ any] int; var x (*(T[int]))`, `*(T[int])`, `*qd15.T[int]`}, // parser doesn't record parens
+               // {`package qd16; type T[_ any] int; var x (*(T[int]))`, `(*(T[int]))`, `*qd16.T[int]`}, // parser doesn't record parens
+
+               // - as ordinary function parameter, generic
+               {`package qe1; type T[_ any] int; func _(T[int])`, `T`, `qe1.T[_ any]`},
+               {`package qe2; type T[_ any] int; func _((T[int]))`, `T[int]`, `qe2.T[int]`},
+               // {`package qe3; type T[_ any] int; func _((T[int]))`, `(T[int])`, `qe3.T[int]`}, // parser doesn't record parens
+               {`package qe4; type T[_ any] int; func _(((T[int])))`, `T`, `qe4.T[_ any]`},
+               // {`package qe5; type T[_ any] int; func _(((T[int])))`, `(T[int])`, `qe5.T[int]`}, // parser doesn't record parens
+               // {`package qe6; type T[_ any] int; func _(((T[int])))`, `((T[int]))`, `qe6.T[int]`}, // parser doesn't record parens
+               {`package qe7; type T[_ any] int; func _(*T[int])`, `T`, `qe7.T[_ any]`},
+               {`package qe8; type T[_ any] int; func _(*T[int])`, `*T[int]`, `*qe8.T[int]`},
+               {`package qe9; type T[_ any] int; func _((*T[int]))`, `T`, `qe9.T[_ any]`},
+               {`package qe10; type T[_ any] int; func _((*T[int]))`, `*T[int]`, `*qe10.T[int]`},
+               {`package qe11; type T[_ any] int; func _(*(T[int]))`, `T[int]`, `qe11.T[int]`},
+               // {`package qe12; type T[_ any] int; func _(*(T[int]))`, `(T[int])`, `qe12.T[int]`}, // parser doesn't record parens
+               // {`package qe13; type T[_ any] int; func _(*(T[int]))`, `*(T[int])`, `*qe13.T[int]`}, // parser doesn't record parens
+               // {`package qe14; type T[_ any] int; func _((*(T[int])))`, `(T[int])`, `qe14.T[int]`}, // parser doesn't record parens
+               // {`package qe15; type T[_ any] int; func _((*(T[int])))`, `*(T[int])`, `*qe15.T[int]`}, // parser doesn't record parens
+               // {`package qe16; type T[_ any] int; func _((*(T[int])))`, `(*(T[int]))`, `*qe16.T[int]`}, // parser doesn't record parens
+
+               // - as method receiver, generic
+               {`package qf1; type T[_ any] int; func (T[_]) _() {}`, `T`, `qf1.T[_ any]`},
+               {`package qf2; type T[_ any] int; func ((T[_])) _() {}`, `T[_]`, `qf2.T[_]`},
+               // {`package qf3; type T[_ any] int; func ((T[_])) _() {}`, `(T[_])`, `qf3.T[_]`}, // parser doesn't record parens
+               {`package qf4; type T[_ any] int; func (((T[_]))) _() {}`, `T`, `qf4.T[_ any]`},
+               // {`package qf5; type T[_ any] int; func (((T[_]))) _() {}`, `(T[_])`, `qf5.T[_]`}, // parser doesn't record parens
+               // {`package qf6; type T[_ any] int; func (((T[_]))) _() {}`, `((T[_]))`, `qf6.T[_]`}, // parser doesn't record parens
+               {`package qf7; type T[_ any] int; func (*T[_]) _() {}`, `T`, `qf7.T[_ any]`},
+               {`package qf8; type T[_ any] int; func (*T[_]) _() {}`, `*T[_]`, `*qf8.T[_]`},
+               {`package qf9; type T[_ any] int; func ((*T[_])) _() {}`, `T`, `qf9.T[_ any]`},
+               {`package qf10; type T[_ any] int; func ((*T[_])) _() {}`, `*T[_]`, `*qf10.T[_]`},
+               {`package qf11; type T[_ any] int; func (*(T[_])) _() {}`, `T[_]`, `qf11.T[_]`},
+               // {`package qf12; type T[_ any] int; func (*(T[_])) _() {}`, `(T[_])`, `qf12.T[_]`}, // parser doesn't record parens
+               // {`package qf13; type T[_ any] int; func (*(T[_])) _() {}`, `*(T[_])`, `*qf13.T[_]`}, // parser doesn't record parens
+               // {`package qf14; type T[_ any] int; func ((*(T[_]))) _() {}`, `(T[_])`, `qf14.T[_]`}, // parser doesn't record parens
+               // {`package qf15; type T[_ any] int; func ((*(T[_]))) _() {}`, `*(T[_])`, `*qf15.T[_]`}, // parser doesn't record parens
+               // {`package qf16; type T[_ any] int; func ((*(T[_]))) _() {}`, `(*(T[_]))`, `*qf16.T[_]`}, // parser doesn't record parens
        }
 
        for _, test := range tests {
index 2be8716d44815144cf87ed7294468c2f2b5b9506..5279d37544bd3a9e3cc2a8b60f6d29b46d30497b 100644 (file)
@@ -1380,7 +1380,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Ty
                x.typ = typ
 
        case *syntax.ParenExpr:
-               // type inference doesn't go past parentheses (targe type T = nil)
+               // type inference doesn't go past parentheses (target type T = nil)
                kind := check.rawExpr(nil, x, e.X, nil, false)
                x.expr = e
                return kind
index 8d597c9e6cfa71575512208caaa53ff7611240df..9cbcbe467c8a7f24f569f5117b58a3f1d1471226 100644 (file)
@@ -148,10 +148,12 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (re
        // Determine the receiver base type.
        var recvType Type = Typ[Invalid]
        if rtparams == nil {
-               // If there are no type parameters, we can simply typecheck rbase.
-               // If rbase denotes a generic type, varType will complain. Further
-               // receiver constraints will be checked later, with validRecv.
-               recvType = check.varType(rbase)
+               // If there are no type parameters, we can simply typecheck rparam.Type.
+               // If that is a generic type, varType will complain.
+               // Further receiver constraints will be checked later, with validRecv.
+               // We use rparam.Type (rather than base) to correctly record pointer
+               // and parentheses in types2.Info (was bug, see go.dev/issue/68639).
+               recvType = check.varType(rparam.Type)
        } else {
                // If there are type parameters, rbase must denote a generic base type.
                var baseType *Named
@@ -201,12 +203,14 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (re
                        }
                        recvType = check.instance(rparam.Type.Pos(), baseType, targs, nil, check.context())
                        check.recordInstance(rbase, targs, recvType)
-               }
-       }
 
-       // Reestablish pointerness if needed (but avoid a pointer to an invalid type).
-       if rptr && isValid(recvType) {
-               recvType = NewPointer(recvType)
+                       // Reestablish pointerness if needed (but avoid a pointer to an invalid type).
+                       if rptr && isValid(recvType) {
+                               recvType = NewPointer(recvType)
+                       }
+
+                       check.recordParenthesizedRecvTypes(rparam.Type, recvType)
+               }
        }
 
        //  Create the receiver parameter.
@@ -229,6 +233,41 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (re
        return
 }
 
+// recordParenthesizedRecvTypes records parenthesized intermediate receiver type
+// expressions that all map to the same type, by recursively unpacking expr and
+// recording the corresponding type for it. Example:
+//
+//     expression  -->  type
+//     ----------------------
+//     (*(T[P]))        *T[P]
+//      *(T[P])         *T[P]
+//       (T[P])          T[P]
+//        T[P]           T[P]
+func (check *Checker) recordParenthesizedRecvTypes(expr syntax.Expr, typ Type) {
+       for {
+               check.recordTypeAndValue(expr, typexpr, typ, nil)
+               switch e := expr.(type) {
+               case *syntax.ParenExpr:
+                       expr = e.X
+               case *syntax.Operation:
+                       if e.Op == syntax.Mul && e.Y == nil {
+                               expr = e.X
+                               // In a correct program, typ must be an unnamed
+                               // pointer type. But be careful and don't panic.
+                               ptr, _ := typ.(*Pointer)
+                               if ptr == nil {
+                                       return // something is wrong
+                               }
+                               typ = ptr.base
+                               break
+                       }
+                       return // cannot unpack any further
+               default:
+                       return // cannot unpack any further
+               }
+       }
+}
+
 // collectParams collects (but does not delare) all parameters of list and returns
 // the list of parameter names, corresponding parameter variables, and whether the
 // parameter list is variadic. Anonymous parameters are recorded with nil names.
index f94fe6be4ccae44f2cea1b91847db0a38672e4d0..febb5893436e4f29fd1f28e5b51ba45dc39fd8e5 100644 (file)
@@ -403,6 +403,116 @@ func TestTypesInfo(t *testing.T) {
                {`package s8; func _() { f(g, h) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func(int, string)`},
                {`package s9; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h`, `func[P, Q any](P, Q)`}, // go.dev/issues/60212
                {`package s10; func _() { f(g, h[int]) }; func f[P any](func(int, P), func(P, string)) {}; func g[P any](P, P) {}; func h[P, Q any](P, Q) {}`, `h[int]`, `func(int, string)`},
+
+               // go.dev/issue/68639
+               // parenthesized and pointer type expressions in various positions
+               // - as variable type, not generic
+               {`package qa1; type T int; var x T`, `T`, `qa1.T`},
+               {`package qa2; type T int; var x (T)`, `T`, `qa2.T`},
+               {`package qa3; type T int; var x (T)`, `(T)`, `qa3.T`},
+               {`package qa4; type T int; var x ((T))`, `T`, `qa4.T`},
+               {`package qa5; type T int; var x ((T))`, `(T)`, `qa5.T`},
+               {`package qa6; type T int; var x ((T))`, `((T))`, `qa6.T`},
+               {`package qa7; type T int; var x *T`, `T`, `qa7.T`},
+               {`package qa8; type T int; var x *T`, `*T`, `*qa8.T`},
+               {`package qa9; type T int; var x (*T)`, `T`, `qa9.T`},
+               {`package qa10; type T int; var x (*T)`, `*T`, `*qa10.T`},
+               {`package qa11; type T int; var x *(T)`, `T`, `qa11.T`},
+               {`package qa12; type T int; var x *(T)`, `(T)`, `qa12.T`},
+               {`package qa13; type T int; var x *(T)`, `*(T)`, `*qa13.T`},
+               {`package qa14; type T int; var x (*(T))`, `(T)`, `qa14.T`},
+               {`package qa15; type T int; var x (*(T))`, `*(T)`, `*qa15.T`},
+               {`package qa16; type T int; var x (*(T))`, `(*(T))`, `*qa16.T`},
+
+               // - as ordinary function parameter, not generic
+               {`package qb1; type T int; func _(T)`, `T`, `qb1.T`},
+               {`package qb2; type T int; func _((T))`, `T`, `qb2.T`},
+               {`package qb3; type T int; func _((T))`, `(T)`, `qb3.T`},
+               {`package qb4; type T int; func _(((T)))`, `T`, `qb4.T`},
+               {`package qb5; type T int; func _(((T)))`, `(T)`, `qb5.T`},
+               {`package qb6; type T int; func _(((T)))`, `((T))`, `qb6.T`},
+               {`package qb7; type T int; func _(*T)`, `T`, `qb7.T`},
+               {`package qb8; type T int; func _(*T)`, `*T`, `*qb8.T`},
+               {`package qb9; type T int; func _((*T))`, `T`, `qb9.T`},
+               {`package qb10; type T int; func _((*T))`, `*T`, `*qb10.T`},
+               {`package qb11; type T int; func _(*(T))`, `T`, `qb11.T`},
+               {`package qb12; type T int; func _(*(T))`, `(T)`, `qb12.T`},
+               {`package qb13; type T int; func _(*(T))`, `*(T)`, `*qb13.T`},
+               {`package qb14; type T int; func _((*(T)))`, `(T)`, `qb14.T`},
+               {`package qb15; type T int; func _((*(T)))`, `*(T)`, `*qb15.T`},
+               {`package qb16; type T int; func _((*(T)))`, `(*(T))`, `*qb16.T`},
+
+               // - as method receiver, not generic
+               {`package qc1; type T int; func (T) _() {}`, `T`, `qc1.T`},
+               {`package qc2; type T int; func ((T)) _() {}`, `T`, `qc2.T`},
+               {`package qc3; type T int; func ((T)) _() {}`, `(T)`, `qc3.T`},
+               {`package qc4; type T int; func (((T))) _() {}`, `T`, `qc4.T`},
+               {`package qc5; type T int; func (((T))) _() {}`, `(T)`, `qc5.T`},
+               {`package qc6; type T int; func (((T))) _() {}`, `((T))`, `qc6.T`},
+               {`package qc7; type T int; func (*T) _() {}`, `T`, `qc7.T`},
+               {`package qc8; type T int; func (*T) _() {}`, `*T`, `*qc8.T`},
+               {`package qc9; type T int; func ((*T)) _() {}`, `T`, `qc9.T`},
+               {`package qc10; type T int; func ((*T)) _() {}`, `*T`, `*qc10.T`},
+               {`package qc11; type T int; func (*(T)) _() {}`, `T`, `qc11.T`},
+               {`package qc12; type T int; func (*(T)) _() {}`, `(T)`, `qc12.T`},
+               {`package qc13; type T int; func (*(T)) _() {}`, `*(T)`, `*qc13.T`},
+               {`package qc14; type T int; func ((*(T))) _() {}`, `(T)`, `qc14.T`},
+               {`package qc15; type T int; func ((*(T))) _() {}`, `*(T)`, `*qc15.T`},
+               {`package qc16; type T int; func ((*(T))) _() {}`, `(*(T))`, `*qc16.T`},
+
+               // - as variable type, generic
+               {`package qd1; type T[_ any] int; var x T[int]`, `T`, `qd1.T[_ any]`},
+               {`package qd2; type T[_ any] int; var x (T[int])`, `T[int]`, `qd2.T[int]`},
+               {`package qd3; type T[_ any] int; var x (T[int])`, `(T[int])`, `qd3.T[int]`},
+               {`package qd4; type T[_ any] int; var x ((T[int]))`, `T`, `qd4.T[_ any]`},
+               {`package qd5; type T[_ any] int; var x ((T[int]))`, `(T[int])`, `qd5.T[int]`},
+               {`package qd6; type T[_ any] int; var x ((T[int]))`, `((T[int]))`, `qd6.T[int]`},
+               {`package qd7; type T[_ any] int; var x *T[int]`, `T`, `qd7.T[_ any]`},
+               {`package qd8; type T[_ any] int; var x *T[int]`, `*T[int]`, `*qd8.T[int]`},
+               {`package qd9; type T[_ any] int; var x (*T[int])`, `T`, `qd9.T[_ any]`},
+               {`package qd10; type T[_ any] int; var x (*T[int])`, `*T[int]`, `*qd10.T[int]`},
+               {`package qd11; type T[_ any] int; var x *(T[int])`, `T[int]`, `qd11.T[int]`},
+               {`package qd12; type T[_ any] int; var x *(T[int])`, `(T[int])`, `qd12.T[int]`},
+               {`package qd13; type T[_ any] int; var x *(T[int])`, `*(T[int])`, `*qd13.T[int]`},
+               {`package qd14; type T[_ any] int; var x (*(T[int]))`, `(T[int])`, `qd14.T[int]`},
+               {`package qd15; type T[_ any] int; var x (*(T[int]))`, `*(T[int])`, `*qd15.T[int]`},
+               {`package qd16; type T[_ any] int; var x (*(T[int]))`, `(*(T[int]))`, `*qd16.T[int]`},
+
+               // - as ordinary function parameter, generic
+               {`package qe1; type T[_ any] int; func _(T[int])`, `T`, `qe1.T[_ any]`},
+               {`package qe2; type T[_ any] int; func _((T[int]))`, `T[int]`, `qe2.T[int]`},
+               {`package qe3; type T[_ any] int; func _((T[int]))`, `(T[int])`, `qe3.T[int]`},
+               {`package qe4; type T[_ any] int; func _(((T[int])))`, `T`, `qe4.T[_ any]`},
+               {`package qe5; type T[_ any] int; func _(((T[int])))`, `(T[int])`, `qe5.T[int]`},
+               {`package qe6; type T[_ any] int; func _(((T[int])))`, `((T[int]))`, `qe6.T[int]`},
+               {`package qe7; type T[_ any] int; func _(*T[int])`, `T`, `qe7.T[_ any]`},
+               {`package qe8; type T[_ any] int; func _(*T[int])`, `*T[int]`, `*qe8.T[int]`},
+               {`package qe9; type T[_ any] int; func _((*T[int]))`, `T`, `qe9.T[_ any]`},
+               {`package qe10; type T[_ any] int; func _((*T[int]))`, `*T[int]`, `*qe10.T[int]`},
+               {`package qe11; type T[_ any] int; func _(*(T[int]))`, `T[int]`, `qe11.T[int]`},
+               {`package qe12; type T[_ any] int; func _(*(T[int]))`, `(T[int])`, `qe12.T[int]`},
+               {`package qe13; type T[_ any] int; func _(*(T[int]))`, `*(T[int])`, `*qe13.T[int]`},
+               {`package qe14; type T[_ any] int; func _((*(T[int])))`, `(T[int])`, `qe14.T[int]`},
+               {`package qe15; type T[_ any] int; func _((*(T[int])))`, `*(T[int])`, `*qe15.T[int]`},
+               {`package qe16; type T[_ any] int; func _((*(T[int])))`, `(*(T[int]))`, `*qe16.T[int]`},
+
+               // - as method receiver, generic
+               {`package qf1; type T[_ any] int; func (T[_]) _() {}`, `T`, `qf1.T[_ any]`},
+               {`package qf2; type T[_ any] int; func ((T[_])) _() {}`, `T[_]`, `qf2.T[_]`},
+               {`package qf3; type T[_ any] int; func ((T[_])) _() {}`, `(T[_])`, `qf3.T[_]`},
+               {`package qf4; type T[_ any] int; func (((T[_]))) _() {}`, `T`, `qf4.T[_ any]`},
+               {`package qf5; type T[_ any] int; func (((T[_]))) _() {}`, `(T[_])`, `qf5.T[_]`},
+               {`package qf6; type T[_ any] int; func (((T[_]))) _() {}`, `((T[_]))`, `qf6.T[_]`},
+               {`package qf7; type T[_ any] int; func (*T[_]) _() {}`, `T`, `qf7.T[_ any]`},
+               {`package qf8; type T[_ any] int; func (*T[_]) _() {}`, `*T[_]`, `*qf8.T[_]`},
+               {`package qf9; type T[_ any] int; func ((*T[_])) _() {}`, `T`, `qf9.T[_ any]`},
+               {`package qf10; type T[_ any] int; func ((*T[_])) _() {}`, `*T[_]`, `*qf10.T[_]`},
+               {`package qf11; type T[_ any] int; func (*(T[_])) _() {}`, `T[_]`, `qf11.T[_]`},
+               {`package qf12; type T[_ any] int; func (*(T[_])) _() {}`, `(T[_])`, `qf12.T[_]`},
+               {`package qf13; type T[_ any] int; func (*(T[_])) _() {}`, `*(T[_])`, `*qf13.T[_]`},
+               {`package qf14; type T[_ any] int; func ((*(T[_]))) _() {}`, `(T[_])`, `qf14.T[_]`},
+               {`package qf15; type T[_ any] int; func ((*(T[_]))) _() {}`, `*(T[_])`, `*qf15.T[_]`},
+               {`package qf16; type T[_ any] int; func ((*(T[_]))) _() {}`, `(*(T[_]))`, `*qf16.T[_]`},
        }
 
        for _, test := range tests {
index ea680b8504df3b74e916199e4bc5ca64c1b93c28..8289de223fff5b38304a0c0563e7fb425b144cef 100644 (file)
@@ -1362,7 +1362,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type)
                x.typ = typ
 
        case *ast.ParenExpr:
-               // type inference doesn't go past parentheses (targe type T = nil)
+               // type inference doesn't go past parentheses (target type T = nil)
                kind := check.rawExpr(nil, x, e.X, nil, false)
                x.expr = e
                return kind
index 69266cf4d92ec23768cdbc7c6e130ccdc617d186..a6cc30242750083b1507a13ae4a07f32d9790441 100644 (file)
@@ -169,10 +169,12 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (recv *
        // Determine the receiver base type.
        var recvType Type = Typ[Invalid]
        if rtparams == nil {
-               // If there are no type parameters, we can simply typecheck rbase.
-               // If rbase denotes a generic type, varType will complain. Further
-               // receiver constraints will be checked later, with validRecv.
-               recvType = check.varType(rbase)
+               // If there are no type parameters, we can simply typecheck rparam.Type.
+               // If that is a generic type, varType will complain.
+               // Further receiver constraints will be checked later, with validRecv.
+               // We use rparam.Type (rather than base) to correctly record pointer
+               // and parentheses in types.Info (was bug, see go.dev/issue/68639).
+               recvType = check.varType(rparam.Type)
        } else {
                // If there are type parameters, rbase must denote a generic base type.
                var baseType *Named
@@ -219,12 +221,14 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (recv *
                        }
                        recvType = check.instance(rparam.Type.Pos(), baseType, targs, nil, check.context())
                        check.recordInstance(rbase, targs, recvType)
-               }
-       }
 
-       // Reestablish pointerness if needed (but avoid a pointer to an invalid type).
-       if rptr && isValid(recvType) {
-               recvType = NewPointer(recvType)
+                       // Reestablish pointerness if needed (but avoid a pointer to an invalid type).
+                       if rptr && isValid(recvType) {
+                               recvType = NewPointer(recvType)
+                       }
+
+                       check.recordParenthesizedRecvTypes(rparam.Type, recvType)
+               }
        }
 
        // Make sure we have no more than one receiver name.
@@ -258,6 +262,37 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (recv *
        return
 }
 
+// recordParenthesizedRecvTypes records parenthesized intermediate receiver type
+// expressions that all map to the same type, by recursively unpacking expr and
+// recording the corresponding type for it. Example:
+//
+//     expression  -->  type
+//     ----------------------
+//     (*(T[P]))        *T[P]
+//      *(T[P])         *T[P]
+//       (T[P])          T[P]
+//        T[P]           T[P]
+func (check *Checker) recordParenthesizedRecvTypes(expr ast.Expr, typ Type) {
+       for {
+               check.recordTypeAndValue(expr, typexpr, typ, nil)
+               switch e := expr.(type) {
+               case *ast.ParenExpr:
+                       expr = e.X
+               case *ast.StarExpr:
+                       expr = e.X
+                       // In a correct program, typ must be an unnamed
+                       // pointer type. But be careful and don't panic.
+                       ptr, _ := typ.(*Pointer)
+                       if ptr == nil {
+                               return // something is wrong
+                       }
+                       typ = ptr.base
+               default:
+                       return // cannot unpack any further
+               }
+       }
+}
+
 // collectParams collects (but does not delare) all parameters of list and returns
 // the list of parameter names, corresponding parameter variables, and whether the
 // parameter list is variadic. Anonymous parameters are recorded with nil names.