]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: record type parameters in receiver expressions as uses
authorRobert Griesemer <gri@golang.org>
Wed, 31 Jul 2024 02:35:27 +0000 (19:35 -0700)
committerGopher Robot <gobot@golang.org>
Wed, 31 Jul 2024 20:27:58 +0000 (20:27 +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, type parameters in receiver type
expressions were only recorded as definitions (in Info.Defs).

Before that CL, such type parameters were simultaneously considered
definitions (they are declared by the receiver type expression) and
uses (they are used to instantiate the receiver type expression).

Adjust the receiver type checking code accordingly and record its
type parameters also in Info.Uses and Info.Types.

While at it, in go/types, replace declareTypeParams (plural) with
declareTypeParam (singular) to more closely match types2 code.
No functionality or semantic change.

Fixes #68670.
For #51343.

Change-Id: Ibbca1a9b92e31b0dc972052a2827deeab49da98b
Reviewed-on: https://go-review.googlesource.com/c/go/+/601935
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Tim King <taking@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
src/cmd/compile/internal/types2/api_test.go
src/cmd/compile/internal/types2/signature.go
src/go/types/api_test.go
src/go/types/decl.go
src/go/types/signature.go

index 2a3c76bb885bcfdee44bc88e515ca0d43f8386f2..d9ba620888078ad3877cc4ac1ebcf2fc1838cc6e 100644 (file)
@@ -515,6 +515,13 @@ func TestTypesInfo(t *testing.T) {
                // {`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 historic reasons, type parameters in receiver type expressions
+               // are considered both definitions and uses and thus also show up in
+               // the Info.Types map (see go.dev/issue/68670).
+               {`package t1; type T[_ any] int; func (T[P]) _() {}`, `P`, `P`},
+               {`package t2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `P`},
+               {`package t3; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `Q`},
        }
 
        for _, test := range tests {
@@ -829,6 +836,11 @@ func TestDefsInfo(t *testing.T) {
                {`package g0; type x[T any] int`, `x`, `type g0.x[T any] int`},
                {`package g1; func f[T any]() {}`, `f`, `func g1.f[T any]()`},
                {`package g2; type x[T any] int; func (*x[_]) m() {}`, `m`, `func (*g2.x[_]).m()`},
+
+               // Type parameters in receiver type expressions are definitions.
+               {`package r0; type T[_ any] int; func (T[P]) _() {}`, `P`, `type parameter P any`},
+               {`package r1; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `type parameter P any`},
+               {`package r2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `type parameter Q any`},
        }
 
        for _, test := range tests {
@@ -894,6 +906,12 @@ func TestUsesInfo(t *testing.T) {
                        `m`,
                        `func (m10.E[int]).m()`,
                },
+
+               // For historic reasons, type parameters in receiver type expressions
+               // are considered both definitions and uses (see go.dev/issue/68670).
+               {`package r0; type T[_ any] int; func (T[P]) _() {}`, `P`, `type parameter P any`},
+               {`package r1; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `type parameter P any`},
+               {`package r2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `type parameter Q any`},
        }
 
        for _, test := range tests {
index 9cbcbe467c8a7f24f569f5117b58a3f1d1471226..8754f5492ceb33d01fe61a6b3a4377e29ee2540b 100644 (file)
@@ -171,7 +171,13 @@ func (check *Checker) collectRecv(rparam *syntax.Field, scopePos syntax.Pos) (re
                // after typechecking rbase (see go.dev/issue/52038).
                recvTParams := make([]*TypeParam, len(rtparams))
                for i, rparam := range rtparams {
-                       recvTParams[i] = check.declareTypeParam(rparam, scopePos)
+                       tpar := check.declareTypeParam(rparam, scopePos)
+                       recvTParams[i] = tpar
+                       // For historic reasons, type parameters in receiver type expressions
+                       // are considered both definitions and uses and thus must be recorded
+                       // in the Info.Uses and Info.Types maps (see go.dev/issue/68670).
+                       check.recordUse(rparam, tpar.obj)
+                       check.recordTypeAndValue(rparam, typexpr, tpar, nil)
                }
                recvTParamsList = bindTParams(recvTParams)
 
index febb5893436e4f29fd1f28e5b51ba45dc39fd8e5..f5bf49b4f8fe5cc3ee6c54627e1c1bfa242fb0f6 100644 (file)
@@ -513,6 +513,13 @@ func TestTypesInfo(t *testing.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 historic reasons, type parameters in receiver type expressions
+               // are considered both definitions and uses and thus also show up in
+               // the Info.Types map (see go.dev/issue/68670).
+               {`package t1; type T[_ any] int; func (T[P]) _() {}`, `P`, `P`},
+               {`package t2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `P`},
+               {`package t3; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `Q`},
        }
 
        for _, test := range tests {
@@ -826,6 +833,11 @@ func TestDefsInfo(t *testing.T) {
                {`package g0; type x[T any] int`, `x`, `type g0.x[T any] int`},
                {`package g1; func f[T any]() {}`, `f`, `func g1.f[T any]()`},
                {`package g2; type x[T any] int; func (*x[_]) m() {}`, `m`, `func (*g2.x[_]).m()`},
+
+               // Type parameters in receiver type expressions are definitions.
+               {`package r0; type T[_ any] int; func (T[P]) _() {}`, `P`, `type parameter P any`},
+               {`package r1; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `type parameter P any`},
+               {`package r2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `type parameter Q any`},
        }
 
        for _, test := range tests {
@@ -893,6 +905,12 @@ func TestUsesInfo(t *testing.T) {
                },
                {`package m11; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `m`, `func (m11.T[int]).m()`},
                {`package m12; type T[A any] interface{ m(); n() }; func _(t1 T[int], t2 T[string]) { t1.m(); t2.n() }`, `n`, `func (m12.T[string]).n()`},
+
+               // For historic reasons, type parameters in receiver type expressions
+               // are considered both definitions and uses (see go.dev/issue/68670).
+               {`package r0; type T[_ any] int; func (T[P]) _() {}`, `P`, `type parameter P any`},
+               {`package r1; type T[_, _ any] int; func (T[P, Q]) _() {}`, `P`, `type parameter P any`},
+               {`package r2; type T[_, _ any] int; func (T[P, Q]) _() {}`, `Q`, `type parameter Q any`},
        }
 
        for _, test := range tests {
index e9bf802cb8b1df11998c4e06f2db984af40144d6..f4bccb5209298a31fb6e77a978f45a5a08a44696 100644 (file)
@@ -674,7 +674,9 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
        // list (so we can have mutually recursive parameterized interfaces).
        scopePos := list.Pos()
        for _, f := range list.List {
-               tparams = check.declareTypeParams(tparams, f.Names, scopePos)
+               for _, name := range f.Names {
+                       tparams = append(tparams, check.declareTypeParam(name, scopePos))
+               }
        }
 
        // Set the type parameters before collecting the type constraints because
@@ -743,25 +745,17 @@ func (check *Checker) bound(x ast.Expr) Type {
        return check.typ(x)
 }
 
-func (check *Checker) declareTypeParams(tparams []*TypeParam, names []*ast.Ident, scopePos token.Pos) []*TypeParam {
+func (check *Checker) declareTypeParam(name *ast.Ident, scopePos token.Pos) *TypeParam {
        // Use Typ[Invalid] for the type constraint to ensure that a type
        // is present even if the actual constraint has not been assigned
        // yet.
        // TODO(gri) Need to systematically review all uses of type parameter
        //           constraints to make sure we don't rely on them if they
        //           are not properly set yet.
-       for _, name := range names {
-               tname := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
-               tpar := check.newTypeParam(tname, Typ[Invalid]) // assigns type to tpar as a side-effect
-               check.declare(check.scope, name, tname, scopePos)
-               tparams = append(tparams, tpar)
-       }
-
-       if check.conf._Trace && len(names) > 0 {
-               check.trace(names[0].Pos(), "type params = %v", tparams[len(tparams)-len(names):])
-       }
-
-       return tparams
+       tname := NewTypeName(name.Pos(), check.pkg, name.Name, nil)
+       tpar := check.newTypeParam(tname, Typ[Invalid]) // assigns type to tname as a side-effect
+       check.declare(check.scope, name, tname, scopePos)
+       return tpar
 }
 
 func (check *Checker) collectMethods(obj *TypeName) {
index a6cc30242750083b1507a13ae4a07f32d9790441..ea25ef49310efa0193fb8b96e6b79ba2a20a34ae 100644 (file)
@@ -190,7 +190,16 @@ func (check *Checker) collectRecv(rparam *ast.Field, scopePos token.Pos) (recv *
                // Checker.collectTypeParams). The scope of the type parameter T in
                // "func (r T[T]) f() {}" starts after f, not at r, so we declare it
                // after typechecking rbase (see go.dev/issue/52038).
-               recvTParams := check.declareTypeParams(nil, rtparams, scopePos)
+               recvTParams := make([]*TypeParam, len(rtparams))
+               for i, rparam := range rtparams {
+                       tpar := check.declareTypeParam(rparam, scopePos)
+                       recvTParams[i] = tpar
+                       // For historic reasons, type parameters in receiver type expressions
+                       // are considered both definitions and uses and thus must be recorded
+                       // in the Info.Uses and Info.Types maps (see go.dev/issue/68670).
+                       check.recordUse(rparam, tpar.obj)
+                       check.recordTypeAndValue(rparam, typexpr, tpar, nil)
+               }
                recvTParamsList = bindTParams(recvTParams)
 
                // Get the type parameter bounds from the receiver base type