mirror of
https://github.com/golang/go
synced 2024-11-23 18:50:05 -07:00
go/types, types2: method recv type parameter count must match base type parameter count
Check receiver type parameter count when type checking the method signature and report a suitable error (don't rely on delayed instantiation and possibly constraint type inference). While at it, simplify blank name recoding and type bound rewriting. Stop-gap measure to avoid crashes in the compiler. Fixes #51339. For #51343. Change-Id: Idbe2d32d69b66573ca973339f8924b349d2bc9cc Reviewed-on: https://go-review.googlesource.com/c/go/+/387836 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
c15527f0b0
commit
c0840a7c72
@ -294,15 +294,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
|
||||
return "(" + strings.Join(res, ", ") + ")"
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
measure := func(x int, unit string) string {
|
||||
s := fmt.Sprintf("%d %s", x, unit)
|
||||
if x != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
func measure(x int, unit string) string {
|
||||
if x != 1 {
|
||||
unit += "s"
|
||||
}
|
||||
return fmt.Sprintf("%d %s", x, unit)
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
|
||||
vars := measure(nvars, "variable")
|
||||
vals := measure(nvals, "value")
|
||||
rhs0 := rhs[0]
|
||||
|
@ -116,11 +116,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
// lookup in the scope.
|
||||
for i, p := range rparams {
|
||||
if p.Value == "_" {
|
||||
tpar := sig.rparams.At(i)
|
||||
if check.recvTParamMap == nil {
|
||||
check.recvTParamMap = make(map[*syntax.Name]*TypeParam)
|
||||
}
|
||||
check.recvTParamMap[p] = tpar
|
||||
check.recvTParamMap[p] = tparams[i]
|
||||
}
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
@ -136,22 +135,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if sig.RecvTypeParams().Len() == len(recvTParams) {
|
||||
// We have a list of *TypeNames but we need a list of Types.
|
||||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
bound := recvTParams[i].bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
if len(tparams) == len(recvTParams) {
|
||||
smap := makeRenameMap(recvTParams, tparams)
|
||||
for i, tpar := range tparams {
|
||||
recvTPar := recvTParams[i]
|
||||
check.mono.recordCanon(tpar, recvTPar)
|
||||
// recvTPar.bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the current
|
||||
// context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
|
||||
}
|
||||
} else if len(tparams) < len(recvTParams) {
|
||||
// Reporting an error here is a stop-gap measure to avoid crashes in the
|
||||
// compiler when a type parameter/argument cannot be inferred later. It
|
||||
// may lead to follow-on errors (see issues #51339, #51343).
|
||||
// TODO(gri) find a better solution
|
||||
got := measure(len(tparams), "type parameter")
|
||||
check.errorf(recvPar, "got %s, but receiver base type declares %d", got, len(recvTParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
vendored
Normal file
16
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is tested when running "go test -run Manual"
|
||||
// without source arguments. Use for one-off debugging.
|
||||
|
||||
package p
|
||||
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
@ -290,15 +290,14 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
|
||||
return "(" + strings.Join(res, ", ") + ")"
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
|
||||
measure := func(x int, unit string) string {
|
||||
s := fmt.Sprintf("%d %s", x, unit)
|
||||
if x != 1 {
|
||||
s += "s"
|
||||
}
|
||||
return s
|
||||
func measure(x int, unit string) string {
|
||||
if x != 1 {
|
||||
unit += "s"
|
||||
}
|
||||
return fmt.Sprintf("%d %s", x, unit)
|
||||
}
|
||||
|
||||
func (check *Checker) assignError(rhs []ast.Expr, nvars, nvals int) {
|
||||
vars := measure(nvars, "variable")
|
||||
vals := measure(nvals, "value")
|
||||
rhs0 := rhs[0]
|
||||
|
@ -112,7 +112,8 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||
// - the receiver specification acts as local declaration for its type parameters, which may be blank
|
||||
_, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true)
|
||||
if len(rparams) > 0 {
|
||||
sig.rparams = bindTParams(check.declareTypeParams(nil, rparams))
|
||||
tparams := check.declareTypeParams(nil, rparams)
|
||||
sig.rparams = bindTParams(tparams)
|
||||
// Blank identifiers don't get declared, so naive type-checking of the
|
||||
// receiver type expression would fail in Checker.collectParams below,
|
||||
// when Checker.ident cannot resolve the _ to a type.
|
||||
@ -122,11 +123,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||
// lookup in the scope.
|
||||
for i, p := range rparams {
|
||||
if p.Name == "_" {
|
||||
tpar := sig.rparams.At(i)
|
||||
if check.recvTParamMap == nil {
|
||||
check.recvTParamMap = make(map[*ast.Ident]*TypeParam)
|
||||
}
|
||||
check.recvTParamMap[p] = tpar
|
||||
check.recvTParamMap[p] = tparams[i]
|
||||
}
|
||||
}
|
||||
// determine receiver type to get its type parameters
|
||||
@ -142,22 +142,23 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
||||
}
|
||||
}
|
||||
// provide type parameter bounds
|
||||
// - only do this if we have the right number (otherwise an error is reported elsewhere)
|
||||
if sig.RecvTypeParams().Len() == len(recvTParams) {
|
||||
// We have a list of *TypeNames but we need a list of Types.
|
||||
list := make([]Type, sig.RecvTypeParams().Len())
|
||||
for i, t := range sig.RecvTypeParams().list() {
|
||||
list[i] = t
|
||||
check.mono.recordCanon(t, recvTParams[i])
|
||||
}
|
||||
smap := makeSubstMap(recvTParams, list)
|
||||
for i, tpar := range sig.RecvTypeParams().list() {
|
||||
bound := recvTParams[i].bound
|
||||
// bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the
|
||||
// current context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, bound, smap, nil)
|
||||
if len(tparams) == len(recvTParams) {
|
||||
smap := makeRenameMap(recvTParams, tparams)
|
||||
for i, tpar := range tparams {
|
||||
recvTPar := recvTParams[i]
|
||||
check.mono.recordCanon(tpar, recvTPar)
|
||||
// recvTPar.bound is (possibly) parameterized in the context of the
|
||||
// receiver type declaration. Substitute parameters for the current
|
||||
// context.
|
||||
tpar.bound = check.subst(tpar.obj.pos, recvTPar.bound, smap, nil)
|
||||
}
|
||||
} else if len(tparams) < len(recvTParams) {
|
||||
// Reporting an error here is a stop-gap measure to avoid crashes in the
|
||||
// compiler when a type parameter/argument cannot be inferred later. It
|
||||
// may lead to follow-on errors (see issues #51339, #51343).
|
||||
// TODO(gri) find a better solution
|
||||
got := measure(len(tparams), "type parameter")
|
||||
check.errorf(recvPar, _BadRecv, "got %s, but receiver base type declares %d", got, len(recvTParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
src/go/types/testdata/fixedbugs/issue51339.go2
vendored
Normal file
16
src/go/types/testdata/fixedbugs/issue51339.go2
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file is tested when running "go test -run Manual"
|
||||
// without source arguments. Use for one-off debugging.
|
||||
|
||||
package p
|
||||
|
||||
type T[P any, B *P] struct{}
|
||||
|
||||
func (T /* ERROR cannot use generic type */ ) m0() {}
|
||||
func (/* ERROR got 1 type parameter, but receiver base type declares 2 */ T[_]) m1() {}
|
||||
func (T[_, _]) m2() {}
|
||||
// TODO(gri) this error is unfortunate (issue #51343)
|
||||
func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {}
|
Loading…
Reference in New Issue
Block a user