From: Robert Griesemer Date: Wed, 31 Jul 2024 02:35:27 +0000 (-0700) Subject: go/types, types2: record type parameters in receiver expressions as uses X-Git-Tag: go1.24rc1~1318 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=385e963e70aaf54a9d96a2c8c28e0a2df3527028;p=gostls13.git 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 Reviewed-by: Tim King LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer --- 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