go/types, types2: record type parameters in receiver expressions as uses

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>
This commit is contained in:
Robert Griesemer 2024-07-30 19:35:27 -07:00 committed by Gopher Robot
parent ab7435abd9
commit 385e963e70
5 changed files with 61 additions and 16 deletions

View 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 {

View 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)

View 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 {

View 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) {

View 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