diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 2a3c76bb88..d9ba620888 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -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 { diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index 9cbcbe467c..8754f5492c 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -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) diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go index febb589343..f5bf49b4f8 100644 --- a/src/go/types/api_test.go +++ b/src/go/types/api_test.go @@ -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 { diff --git a/src/go/types/decl.go b/src/go/types/decl.go index e9bf802cb8..f4bccb5209 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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) { diff --git a/src/go/types/signature.go b/src/go/types/signature.go index a6cc302427..ea25ef4931 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -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