go/types, types2: better error messages for invalid calls

Rather than reporting "non-function" for an invalid type parameter,
report which type in the type parameter's type set is not a function.

Change-Id: I8beec25cc337bae8e03d23e62d97aa82db46bab4
Reviewed-on: https://go-review.googlesource.com/c/go/+/654475
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Robert Griesemer 2025-03-03 18:06:48 -08:00 committed by Gopher Robot
parent 8b7e376e71
commit 584e631023
7 changed files with 26 additions and 26 deletions

View File

@ -244,19 +244,19 @@ func (check *Checker) callExpr(x *operand, call *syntax.CallExpr) exprKind {
// If the operand type is a type parameter, all types in its type set // If the operand type is a type parameter, all types in its type set
// must have a common underlying type, which must be a signature. // must have a common underlying type, which must be a signature.
// TODO(gri) use commonUnder condition for better error message u, err := commonUnder(x.typ, func(t, u Type) *errorCause {
u, err := commonUnder(x.typ, nil) if _, ok := u.(*Signature); u != nil && !ok {
sig, _ := u.(*Signature) return newErrorCause("%s is not a function", t)
if sig == nil {
if err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
} else {
check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
} }
return nil
})
if err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
x.mode = invalid x.mode = invalid
x.expr = call x.expr = call
return statement return statement
} }
sig := u.(*Signature) // u must be a signature per the commonUnder condition
// Capture wasGeneric before sig is potentially instantiated below. // Capture wasGeneric before sig is potentially instantiated below.
wasGeneric := sig.TypeParams().Len() > 0 wasGeneric := sig.TypeParams().Len() > 0

View File

@ -246,19 +246,19 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind {
// If the operand type is a type parameter, all types in its type set // If the operand type is a type parameter, all types in its type set
// must have a common underlying type, which must be a signature. // must have a common underlying type, which must be a signature.
// TODO(gri) use commonUnder condition for better error message u, err := commonUnder(x.typ, func(t, u Type) *errorCause {
u, err := commonUnder(x.typ, nil) if _, ok := u.(*Signature); u != nil && !ok {
sig, _ := u.(*Signature) return newErrorCause("%s is not a function", t)
if sig == nil {
if err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
} else {
check.errorf(x, InvalidCall, invalidOp+"cannot call non-function %s", x)
} }
return nil
})
if err != nil {
check.errorf(x, InvalidCall, invalidOp+"cannot call %s: %s", x, err.format(check))
x.mode = invalid x.mode = invalid
x.expr = call x.expr = call
return statement return statement
} }
sig := u.(*Signature) // u must be a signature per the commonUnder condition
// Capture wasGeneric before sig is potentially instantiated below. // Capture wasGeneric before sig is potentially instantiated below.
wasGeneric := sig.TypeParams().Len() > 0 wasGeneric := sig.TypeParams().Len() > 0

View File

@ -11,7 +11,7 @@ func _() {
x, aBc int x, aBc int
} }
_ = s.x _ = s.x
_ = s /* ERROR "invalid operation: cannot call non-function s.x (variable of type int)" */ .x() _ = s /* ERROR "invalid operation: cannot call s.x (variable of type int): int is not a function" */ .x()
_ = s.X // ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)" _ = s.X // ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)"
_ = s.X /* ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)" */ () _ = s.X /* ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)" */ ()
@ -26,7 +26,7 @@ func _() {
} }
var s S var s S
_ = s.x _ = s.x
_ = s /* ERROR "invalid operation: cannot call non-function s.x (variable of type int)" */ .x() _ = s /* ERROR "invalid operation: cannot call s.x (variable of type int): int is not a function" */ .x()
_ = s.X // ERROR "s.X undefined (type S has no field or method X, but does have field x)" _ = s.X // ERROR "s.X undefined (type S has no field or method X, but does have field x)"
_ = s.X /* ERROR "s.X undefined (type S has no field or method X, but does have field x)" */ () _ = s.X /* ERROR "s.X undefined (type S has no field or method X, but does have field x)" */ ()
} }
@ -77,9 +77,9 @@ func _[P any](x P) {
} }
func _[P int](x P) { func _[P int](x P) {
x /* ERROR "cannot call non-function x (variable of type P constrained by int)" */ () x /* ERROR "cannot call x (variable of type P constrained by int): int is not a function" */ ()
} }
func _[P int | string](x P) { func _[P int | string](x P) {
x /* ERROR "cannot call x (variable of type P constrained by int | string): int and string have different underlying types" */ () x /* ERROR "cannot call x (variable of type P constrained by int | string): int is not a function" */ ()
} }

View File

@ -13,7 +13,7 @@ const P = 2 // declare P to avoid noisy 'undefined' errors below.
// The following parse as invalid array types due to parsing ambiguitiues. // The following parse as invalid array types due to parsing ambiguitiues.
type _ [P *int /* ERROR "int (type) is not an expression" */ ]int type _ [P *int /* ERROR "int (type) is not an expression" */ ]int
type _ [P /* ERROR "non-function P" */ (*int)]int type _ [P /* ERROR "cannot call P (untyped int constant 2): untyped int is not a function" */ (*int)]int
// Adding a trailing comma or an enclosing interface resolves the ambiguity. // Adding a trailing comma or an enclosing interface resolves the ambiguity.
type _[P *int,] int type _[P *int,] int

View File

@ -6,4 +6,4 @@
package main package main
const A = complex(0()) // ERROR "cannot call non-function" const A = complex(0()) // ERROR "cannot call .* not a function"

View File

@ -13,7 +13,7 @@ func F() {
slice := []int{1, 2, 3} slice := []int{1, 2, 3}
_ = slice _ = slice
len := int(2) len := int(2)
println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function|cannot call non-function len" println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function|cannot call len"
const iota = 1 const iota = 1
println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function|cannot call non-function iota" println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function|cannot call iota"
} }

View File

@ -11,9 +11,9 @@ package p
var a = []int{1,2,3} var a = []int{1,2,3}
func _(len int) { func _(len int) {
_ = len(a) // ERROR "cannot call non-function|expected function" _ = len(a) // ERROR "cannot call|expected function"
} }
var cap = false var cap = false
var _ = cap(a) // ERROR "cannot call non-function|expected function" var _ = cap(a) // ERROR "cannot call|expected function"