]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: fix printing of error message with variadic calls
authorRobert Griesemer <gri@golang.org>
Wed, 27 Nov 2024 19:36:53 +0000 (11:36 -0800)
committerGopher Robot <gobot@golang.org>
Wed, 27 Nov 2024 20:50:39 +0000 (20:50 +0000)
Distinguish between variadic signatures and argument lists to
(possibly variadic) functions and place `...` before or after
the last type in the list of types.

Fixes a panic.

Fixes #70526.

Change-Id: I77aba8f50984a21ebcdb62582030f2d0fe0eb097
Reviewed-on: https://go-review.googlesource.com/c/go/+/632275
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/call.go
src/go/types/assignments.go
src/go/types/call.go
src/internal/types/testdata/fixedbugs/issue70150.go
src/internal/types/testdata/fixedbugs/issue70526.go [new file with mode: 0644]

index 382ce2d1ddbd2f58a8262b71a5d44460767ae31a..ebe9ef11cb30b83a9b0b5facad6336722d21d865 100644 (file)
@@ -295,7 +295,11 @@ func varTypes(list []*Var) (res []Type) {
 // ti's are user-friendly string representations for the given types.
 // If variadic is set and the last type is a slice, its string is of
 // the form "...E" where E is the slice's element type.
-func (check *Checker) typesSummary(list []Type, variadic bool) string {
+// If hasDots is set, the last argument string is of the form "T..."
+// where T is the last type.
+// Only one of variadic and hasDots may be set.
+func (check *Checker) typesSummary(list []Type, variadic, hasDots bool) string {
+       assert(!(variadic && hasDots))
        var res []string
        for i, t := range list {
                var s string
@@ -304,7 +308,7 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
                        fallthrough // should not happen but be cautious
                case !isValid(t):
                        s = "unknown type"
-               case isUntyped(t):
+               case isUntyped(t): // => *Basic
                        if isNumeric(t) {
                                // Do not imply a specific type requirement:
                                // "have number, want float64" is better than
@@ -316,12 +320,22 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
                                // for compactness.
                                s = strings.Replace(t.(*Basic).name, "untyped ", "", -1)
                        }
-               case variadic && i == len(list)-1:
-                       s = check.sprintf("...%s", t.(*Slice).elem)
-               }
-               if s == "" {
+               default:
                        s = check.sprintf("%s", t)
                }
+               // handle ... parameters/arguments
+               if i == len(list)-1 {
+                       switch {
+                       case variadic:
+                               // In correct code, the parameter type is a slice, but be careful.
+                               if t, _ := t.(*Slice); t != nil {
+                                       s = check.sprintf("%s", t.elem)
+                               }
+                               s = "..." + s
+                       case hasDots:
+                               s += "..."
+                       }
+               }
                res = append(res, s)
        }
        return "(" + strings.Join(res, ", ") + ")"
@@ -359,8 +373,8 @@ func (check *Checker) returnError(at poser, lhs []*Var, rhs []*operand) {
        }
        err := check.newError(WrongResultCount)
        err.addf(at, "%s return values", qualifier)
-       err.addf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false))
-       err.addf(nopos, "want %s", check.typesSummary(varTypes(lhs), false))
+       err.addf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false, false))
+       err.addf(nopos, "want %s", check.typesSummary(varTypes(lhs), false, false))
        err.report()
 }
 
index 8dbf9df33a98f11879e590a40ab27fd2efca61f0..ae2ab5f9849bc96cd8a2a0502aeefdf84ee046f2 100644 (file)
@@ -530,8 +530,8 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
                }
                err := check.newError(WrongArgCount)
                err.addf(at, "%s arguments in call to %s", qualifier, call.Fun)
-               err.addf(nopos, "have %s", check.typesSummary(operandTypes(args), ddd))
-               err.addf(nopos, "want %s", check.typesSummary(varTypes(params), sig.variadic))
+               err.addf(nopos, "have %s", check.typesSummary(operandTypes(args), false, ddd))
+               err.addf(nopos, "want %s", check.typesSummary(varTypes(params), sig.variadic, false))
                err.report()
                return
        }
index 01a55d582fc95de8895b70213e47955eff8a8d5e..20d400bf1e894795fad0845a05d97bf4faaba8f5 100644 (file)
@@ -298,7 +298,11 @@ func varTypes(list []*Var) (res []Type) {
 // ti's are user-friendly string representations for the given types.
 // If variadic is set and the last type is a slice, its string is of
 // the form "...E" where E is the slice's element type.
-func (check *Checker) typesSummary(list []Type, variadic bool) string {
+// If hasDots is set, the last argument string is of the form "T..."
+// where T is the last type.
+// Only one of variadic and hasDots may be set.
+func (check *Checker) typesSummary(list []Type, variadic, hasDots bool) string {
+       assert(!(variadic && hasDots))
        var res []string
        for i, t := range list {
                var s string
@@ -307,7 +311,7 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
                        fallthrough // should not happen but be cautious
                case !isValid(t):
                        s = "unknown type"
-               case isUntyped(t):
+               case isUntyped(t): // => *Basic
                        if isNumeric(t) {
                                // Do not imply a specific type requirement:
                                // "have number, want float64" is better than
@@ -319,12 +323,22 @@ func (check *Checker) typesSummary(list []Type, variadic bool) string {
                                // for compactness.
                                s = strings.Replace(t.(*Basic).name, "untyped ", "", -1)
                        }
-               case variadic && i == len(list)-1:
-                       s = check.sprintf("...%s", t.(*Slice).elem)
-               }
-               if s == "" {
+               default:
                        s = check.sprintf("%s", t)
                }
+               // handle ... parameters/arguments
+               if i == len(list)-1 {
+                       switch {
+                       case variadic:
+                               // In correct code, the parameter type is a slice, but be careful.
+                               if t, _ := t.(*Slice); t != nil {
+                                       s = check.sprintf("%s", t.elem)
+                               }
+                               s = "..." + s
+                       case hasDots:
+                               s += "..."
+                       }
+               }
                res = append(res, s)
        }
        return "(" + strings.Join(res, ", ") + ")"
@@ -362,8 +376,8 @@ func (check *Checker) returnError(at positioner, lhs []*Var, rhs []*operand) {
        }
        err := check.newError(WrongResultCount)
        err.addf(at, "%s return values", qualifier)
-       err.addf(noposn, "have %s", check.typesSummary(operandTypes(rhs), false))
-       err.addf(noposn, "want %s", check.typesSummary(varTypes(lhs), false))
+       err.addf(noposn, "have %s", check.typesSummary(operandTypes(rhs), false, false))
+       err.addf(noposn, "want %s", check.typesSummary(varTypes(lhs), false, false))
        err.report()
 }
 
index 6db746e4089568d6545130778ddb0b064fa4d1cc..200068b17600547a7eff643458360a776d3f7153 100644 (file)
@@ -530,8 +530,8 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
                }
                err := check.newError(WrongArgCount)
                err.addf(at, "%s arguments in call to %s", qualifier, call.Fun)
-               err.addf(noposn, "have %s", check.typesSummary(operandTypes(args), ddd))
-               err.addf(noposn, "want %s", check.typesSummary(varTypes(params), sig.variadic))
+               err.addf(noposn, "have %s", check.typesSummary(operandTypes(args), false, ddd))
+               err.addf(noposn, "want %s", check.typesSummary(varTypes(params), sig.variadic, false))
                err.report()
                return
        }
index ea308cfddb800b64b4b019bc3cef89a4f533b7d9..5baf4a66306b05be6fbff1edc98b9a5500af9388 100644 (file)
@@ -7,8 +7,8 @@ package p
 func _() {
        var values []int
        vf(values /* ERROR "(variable of type []int) as string value" */)
-       vf(values...) /* ERROR "have (...int)" */
-       vf("ab", "cd", values /* ERROR "have (string, string, ...int)" */ ...)
+       vf(values...) /* ERROR "have ([]int...)\n\twant (string, ...int)" */
+       vf("ab", "cd", values /* ERROR "have (string, string, []int...)\n\twant (string, ...int)" */ ...)
 }
 
 func vf(method string, values ...int) {
diff --git a/src/internal/types/testdata/fixedbugs/issue70526.go b/src/internal/types/testdata/fixedbugs/issue70526.go
new file mode 100644 (file)
index 0000000..56b20bf
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2024 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.
+
+package p
+
+func f(...any)
+
+func _(x int, s []int) {
+       f(0, x /* ERROR "have (number, int...)\n\twant (...any)" */ ...)
+       f(0, s /* ERROR "have (number, []int...)\n\twant (...any)" */ ...)
+       f(0, 0 /* ERROR "have (number, number...)\n\twant (...any)" */ ...)
+}