cmd/compile: fix error message for mismatch between the number of type params and arguments

Fixes #64276

Change-Id: Ib6651669904e6ea0daf275d85d8bd008b8b21cc6
Reviewed-on: https://go-review.googlesource.com/c/go/+/544018
Reviewed-by: raghvender sundarjee <raghvenders@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Raghvender 2023-11-20 19:43:13 -06:00 committed by Gopher Robot
parent 788a227759
commit 4bf1ca4b0c
13 changed files with 100 additions and 70 deletions

View file

@ -122,7 +122,8 @@ func (check *Checker) instance(pos syntax.Pos, orig Type, targs []Type, expandin
assert(expanding == nil) // function instances cannot be reached from Named types
tparams := orig.TypeParams()
if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
return Typ[Invalid]
}
if tparams.Len() == 0 {
@ -150,19 +151,27 @@ func (check *Checker) instance(pos syntax.Pos, orig Type, targs []Type, expandin
return updateContexts(res)
}
// validateTArgLen verifies that the length of targs and tparams matches,
// reporting an error if not. If validation fails and check is nil,
// validateTArgLen panics.
func (check *Checker) validateTArgLen(pos syntax.Pos, ntparams, ntargs int) bool {
if ntargs != ntparams {
// TODO(gri) provide better error message
if check != nil {
check.errorf(pos, WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams)
return false
}
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
// validateTArgLen checks that the number of type arguments (got) matches the
// number of type parameters (want); if they don't match an error is reported.
// If validation fails and check is nil, validateTArgLen panics.
func (check *Checker) validateTArgLen(pos syntax.Pos, name string, want, got int) bool {
var qual string
switch {
case got < want:
qual = "not enough"
case got > want:
qual = "too many"
default:
return true
}
return true
msg := check.sprintf("%s type arguments for type %s: have %d, want %d", qual, name, got, want)
if check != nil {
check.error(atPos(pos), WrongTypeArgCount, msg)
return false
}
panic(fmt.Sprintf("%v: %s", pos, msg))
}
func (check *Checker) verify(pos syntax.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) {

View file

@ -463,7 +463,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *
// errors.
check.recordInstance(x, inst.TypeArgs().list(), inst)
if check.validateTArgLen(x.Pos(), inst.TypeParams().Len(), inst.TypeArgs().Len()) {
if check.validateTArgLen(x.Pos(), inst.obj.name, inst.TypeParams().Len(), inst.TypeArgs().Len()) {
if i, err := check.verify(x.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), check.context()); err != nil {
// best position for error reporting
pos := x.Pos()

View file

@ -124,7 +124,8 @@ func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding
assert(expanding == nil) // function instances cannot be reached from Named types
tparams := orig.TypeParams()
if !check.validateTArgLen(pos, tparams.Len(), len(targs)) {
// TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here)
if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) {
return Typ[Invalid]
}
if tparams.Len() == 0 {
@ -152,19 +153,27 @@ func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding
return updateContexts(res)
}
// validateTArgLen verifies that the length of targs and tparams matches,
// reporting an error if not. If validation fails and check is nil,
// validateTArgLen panics.
func (check *Checker) validateTArgLen(pos token.Pos, ntparams, ntargs int) bool {
if ntargs != ntparams {
// TODO(gri) provide better error message
if check != nil {
check.errorf(atPos(pos), WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams)
return false
}
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
// validateTArgLen checks that the number of type arguments (got) matches the
// number of type parameters (want); if they don't match an error is reported.
// If validation fails and check is nil, validateTArgLen panics.
func (check *Checker) validateTArgLen(pos token.Pos, name string, want, got int) bool {
var qual string
switch {
case got < want:
qual = "not enough"
case got > want:
qual = "too many"
default:
return true
}
return true
msg := check.sprintf("%s type arguments for type %s: have %d, want %d", qual, name, got, want)
if check != nil {
check.error(atPos(pos), WrongTypeArgCount, msg)
return false
}
panic(fmt.Sprintf("%v: %s", pos, msg))
}
func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type, ctxt *Context) (int, error) {

View file

@ -454,7 +454,7 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName)
// errors.
check.recordInstance(ix.Orig, inst.TypeArgs().list(), inst)
if check.validateTArgLen(ix.Pos(), inst.TypeParams().Len(), inst.TypeArgs().Len()) {
if check.validateTArgLen(ix.Pos(), inst.obj.name, inst.TypeParams().Len(), inst.TypeArgs().Len()) {
if i, err := check.verify(ix.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), check.context()); err != nil {
// best position for error reporting
pos := ix.Pos()

View file

@ -8,8 +8,9 @@ package typeInference
// basic inference
type Tb[P ~*Q, Q any] int
func _() {
var x Tb /* ERROR "got 1 arguments" */ [*int]
var x Tb /* ERROR "not enough type arguments for type Tb: have 1, want 2" */ [*int]
var y Tb[*int, int]
x = y /* ERRORx `cannot use y .* in assignment` */
_ = x
@ -17,8 +18,9 @@ func _() {
// recursive inference
type Tr[A any, B *C, C *D, D *A] int
func _() {
var x Tr /* ERROR "got 1 arguments" */ [string]
var x Tr /* ERROR "not enough type arguments for type Tr: have 1, want 4" */ [string]
var y Tr[string, ***string, **string, *string]
var z Tr[int, ***int, **int, *int]
x = y /* ERRORx `cannot use y .* in assignment` */
@ -28,22 +30,30 @@ func _() {
// other patterns of inference
type To0[A any, B []A] int
type To1[A any, B struct{a A}] int
type To1[A any, B struct{ a A }] int
type To2[A any, B [][]A] int
type To3[A any, B [3]*A] int
type To4[A any, B any, C struct{a A; b B}] int
type To4[A any, B any, C struct {
a A
b B
}] int
func _() {
var _ To0 /* ERROR "got 1 arguments" */ [int]
var _ To1 /* ERROR "got 1 arguments" */ [int]
var _ To2 /* ERROR "got 1 arguments" */ [int]
var _ To3 /* ERROR "got 1 arguments" */ [int]
var _ To4 /* ERROR "got 2 arguments" */ [int, string]
var _ To0 /* ERROR "not enough type arguments for type To0: have 1, want 2" */ [int]
var _ To1 /* ERROR "not enough type arguments for type To1: have 1, want 2" */ [int]
var _ To2 /* ERROR "not enough type arguments for type To2: have 1, want 2" */ [int]
var _ To3 /* ERROR "not enough type arguments for type To3: have 1, want 2" */ [int]
var _ To4 /* ERROR "not enough type arguments for type To4: have 2, want 3" */ [int, string]
}
// failed inference
type Tf0[A, B any] int
type Tf1[A any, B ~struct{a A; c C}, C any] int
type Tf1[A any, B ~struct {
a A
c C
}, C any] int
func _() {
var _ Tf0 /* ERROR "got 1 arguments but 2 type parameters" */ [int]
var _ Tf1 /* ERROR "got 1 arguments but 3 type parameters" */ [int]
var _ Tf0 /* ERROR "not enough type arguments for type Tf0: have 1, want 2" */ [int]
var _ Tf1 /* ERROR "not enough type arguments for type Tf1: have 1, want 3" */ [int]
}

View file

@ -42,7 +42,7 @@ type _ myInt /* ERROR "not a generic type" */ [] // ERROR "expected type argumen
// TODO(gri) better error messages
type _ T1[] // ERROR "expected type argument list"
type _ T1[x /* ERROR "not a type" */ ]
type _ T1 /* ERROR "got 2 arguments but 1 type parameters" */ [int, float32]
type _ T1 /* ERROR "too many type arguments for type T1: have 2, want 1" */ [int, float32]
var _ T2[int] = T2[int]{}

View file

@ -13,7 +13,7 @@ func (S[A, B]) m() {}
// TODO(gri): with type-type inference enabled we should only report one error
// below. See issue #50588.
func _[A any](s S /* ERROR "got 1 arguments but 2 type parameters" */ [A]) {
func _[A any](s S /* ERROR "not enough type arguments for type S: have 1, want 2" */ [A]) {
// we should see no follow-on errors below
s.f = 1
s.m()
@ -22,7 +22,7 @@ func _[A any](s S /* ERROR "got 1 arguments but 2 type parameters" */ [A]) {
// another test case from the issue
func _() {
X /* ERROR "cannot infer Q" */ (Interface[*F /* ERROR "got 1 arguments but 2 type parameters" */ [string]](Impl{}))
X /* ERROR "cannot infer Q" */ (Interface[*F /* ERROR "not enough type arguments for type F: have 1, want 2" */ [string]](Impl{}))
}
func X[Q Qer](fs Interface[Q]) {

View file

@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) {
func _() {
// TODO(gri) only report one error below (issue #50932)
var x F /* ERROR "got 1 arguments but 2 type parameters" */ [int]
var x F /* ERROR "not enough type arguments for type F: have 1, want 2" */ [int]
G(x /* ERROR "does not match" */)
}
@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) {
fmt.Println(c)
}
func MMD[Rc RC /* ERROR "got 1 arguments" */ [RG], RG any, G any]() M /* ERROR "got 2 arguments" */ [Rc, RG] {
func MMD[Rc RC /* ERROR "not enough type arguments for type RC: have 1, want 2" */ [RG], RG any, G any]() M /* ERROR "not enough type arguments for type" */ [Rc, RG] {
var nFn NFn /* ERROR "got 2 arguments" */ [Rc, RG]
var nFn NFn /* ERROR "not enough type arguments for type NFn: have 2, want 3" */ [Rc, RG]
var empty Rc
switch any(empty).(type) {
@ -58,11 +58,11 @@ func MMD[Rc RC /* ERROR "got 1 arguments" */ [RG], RG any, G any]() M /* ERROR "
nFn = NSG /* ERROR "cannot use NSG[G]" */ [G]
}
return M /* ERROR "got 2 arguments" */ [Rc, RG]{
return M /* ERROR "not enough type arguments for type M: have 2, want 3" */ [Rc, RG]{
Fn: func(rc Rc) {
NC(nFn /* ERROR "does not match" */ )
NC(nFn /* ERROR "does not match" */)
},
}
return M /* ERROR "got 2 arguments" */ [Rc, RG]{}
return M /* ERROR "not enough type arguments for type M: have 2, want 3" */ [Rc, RG]{}
}

View file

@ -11,20 +11,20 @@ type RC[RG any] interface {
type Fn[RCT RC[RG], RG any] func(RCT)
type F[RCT RC[RG], RG any] interface {
Fn() Fn /* ERROR "got 1 arguments" */ [RCT]
Fn() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT]
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn func() Fn /* ERROR "got 1 arguments" */ [RCT]
makeFn func() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT]
}
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR "got 1 arguments" */ [RCT] {
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT] {
return c.makeFn()
}
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR "got 1 arguments" */ [RCT] {
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR "not enough type arguments for type F: have 1, want 2" */ [RCT] {
// TODO(rfindley): eliminate the duplicate error below.
return & /* ERRORx `cannot use .* as F\[RCT\]` */ concreteF /* ERROR "got 1 arguments" */ [RCT]{
return & /* ERRORx `cannot use .* as F\[RCT\]` */ concreteF /* ERROR "not enough type arguments for type concreteF: have 1, want 2" */ [RCT]{
makeFn: nil,
}
}

View file

@ -12,16 +12,16 @@ type RC[RG any] interface {
type Fn[RCT RC[RG], RG any] func(RCT)
type FFn[RCT RC[RG], RG any] func() Fn /* ERROR "got 1 arguments" */ [RCT]
type FFn[RCT RC[RG], RG any] func() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT]
type F[RCT RC[RG], RG any] interface {
Fn() Fn /* ERROR "got 1 arguments" */ [RCT]
Fn() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT]
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn FFn /* ERROR "got 1 arguments" */ [RCT]
makeFn FFn /* ERROR "not enough type arguments for type FFn: have 1, want 2" */ [RCT]
}
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR "got 1 arguments" */ [RCT] {
func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR "not enough type arguments for type Fn: have 1, want 2" */ [RCT] {
return c.makeFn()
}

View file

@ -9,10 +9,12 @@ package p
type T[P any, B *P] struct{}
func (T /* ERROR "cannot use generic type" */ ) m0() {}
func (T /* ERROR "cannot use generic type" */) m0() {}
// TODO(rfindley): eliminate the duplicate errors here.
func (/* ERROR "got 1 type parameter, but receiver base type declares 2" */ T /* ERROR "got 1 arguments but 2 type parameters" */ [_]) m1() {}
func ( /* ERROR "got 1 type parameter, but receiver base type declares 2" */ T /* ERROR "not enough type arguments for type" */ [_]) m1() {
}
func (T[_, _]) m2() {}
// TODO(gri) this error is unfortunate (issue #51343)
func (T /* ERROR "got 3 arguments but 2 type parameters" */ [_, _, _]) m3() {}
func (T /* ERROR "too many type arguments for type" */ [_, _, _]) m3() {}

View file

@ -13,19 +13,19 @@ type RC[RG any] interface {
type Fn[RCT RC[RG], RG any] func(RCT)
type F[RCT RC[RG], RG any] interface {
Fn() Fn[RCT] // ERROR "got 1 arguments"
Fn() Fn[RCT] // ERROR "not enough type arguments for type Fn: have 1, want 2"
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn func() Fn[RCT] // ERROR "got 1 arguments"
makeFn func() Fn[RCT] // ERROR "not enough type arguments for type Fn: have 1, want 2"
}
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments"
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "not enough type arguments for type Fn: have 1, want 2"
return c.makeFn()
}
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { // ERROR "got 1 arguments"
return &concreteF[RCT]{ // ERROR "cannot use" "got 1 arguments"
func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { // ERROR "not enough type arguments for type F: have 1, want 2"
return &concreteF[RCT]{ // ERROR "cannot use" "not enough type arguments for type concreteF: have 1, want 2"
makeFn: nil,
}
}

View file

@ -13,16 +13,16 @@ type RC[RG any] interface {
type Fn[RCT RC[RG], RG any] func(RCT)
type FFn[RCT RC[RG], RG any] func() Fn[RCT] // ERROR "got 1 arguments"
type FFn[RCT RC[RG], RG any] func() Fn[RCT] // ERROR "not enough type arguments for type Fn: have 1, want 2"
type F[RCT RC[RG], RG any] interface {
Fn() Fn[RCT] // ERROR "got 1 arguments"
Fn() Fn[RCT] // ERROR "not enough type arguments for type Fn: have 1, want 2"
}
type concreteF[RCT RC[RG], RG any] struct {
makeFn FFn[RCT] // ERROR "got 1 arguments"
makeFn FFn[RCT] // ERROR "not enough type arguments for type FFn: have 1, want 2"
}
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "got 1 arguments"
func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { // ERROR "not enough type arguments for type Fn: have 1, want 2"
return c.makeFn()
}