1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:14:45 -07:00

go/types: don't allow f()... if f() is multi-valued

Also: Better position for error messages related to wrong use of ... .

Fixes #9473.

Change-Id: I90565f51a42897b7292f651a84a23611a5d8f359
Reviewed-on: https://go-review.googlesource.com/2390
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Robert Griesemer 2015-01-06 15:10:57 -08:00
parent 4ad370efaa
commit 44ee65f545
6 changed files with 63 additions and 20 deletions

View File

@ -48,7 +48,6 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// make argument getter
arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
if arg == nil {
x.mode = invalid
return
}
// evaluate first argument, if present

View File

@ -179,14 +179,18 @@ func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
// arguments checks argument passing for the call with the given signature.
// The arg function provides the operand for the i'th argument.
func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
passSlice := false
if call.Ellipsis.IsValid() {
// last argument is of the form x...
if sig.variadic {
passSlice = true
} else {
if len(call.Args) == 1 && n > 1 {
// f()... is not permitted if f() is multi-valued
check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
check.useGetter(arg, n)
return
}
if !sig.variadic {
check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
// ok to continue
check.useGetter(arg, n)
return
}
}
@ -194,7 +198,11 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
for i := 0; i < n; i++ {
arg(x, i)
if x.mode != invalid {
check.argument(sig, i, x, passSlice && i == n-1)
var ellipsis token.Pos
if i == n-1 && call.Ellipsis.IsValid() {
ellipsis = call.Ellipsis
}
check.argument(sig, i, x, ellipsis)
}
}
@ -211,8 +219,8 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
}
// argument checks passing of argument x to the i'th parameter of the given signature.
// If passSlice is set, the argument is followed by ... in the call.
func (check *Checker) argument(sig *Signature, i int, x *operand, passSlice bool) {
// If ellipsis is valid, the argument is followed by ... at that position in the call.
func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
n := sig.params.Len()
// determine parameter type
@ -232,13 +240,19 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, passSlice bool
return
}
if passSlice {
if ellipsis.IsValid() {
// argument is of the form x...
if i != n-1 {
check.errorf(x.pos(), "can only use ... with matching parameter")
check.errorf(ellipsis, "can only use ... with matching parameter")
return
}
if _, ok := x.typ.Underlying().(*Slice); !ok {
switch t := x.typ.Underlying().(type) {
case *Slice:
// ok
case *Tuple:
check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
return
default:
check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
return
}

View File

@ -137,7 +137,7 @@ func (check *Checker) reportCycle(cycle []*objNode, i int) {
obj := cycle[i].obj
check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
// print cycle
for _ = range cycle {
for range cycle {
check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
i++
if i >= len(cycle) {

View File

@ -24,11 +24,11 @@ func append1() {
_ = append(s, b)
_ = append(s, x /* ERROR cannot pass argument x */ )
_ = append(s, s /* ERROR cannot pass argument s */ )
_ = append(s /* ERROR can only use ... with matching parameter */ ...)
_ = append(s, b, s /* ERROR can only use ... with matching parameter */ ...)
_ = append(s... /* ERROR can only use ... with matching parameter */ )
_ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
_ = append(s, 1, 2, 3)
_ = append(s, 1, 2, 3, x /* ERROR cannot pass argument x */ , 5, 6, 6)
_ = append(s, 1, 2, s /* ERROR can only use ... with matching parameter */ ...)
_ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
type S []byte

View File

@ -439,7 +439,7 @@ func _calls() {
fv(s /* ERROR "cannot pass" */ )
fv(s...)
fv(x /* ERROR "cannot use" */ ...)
fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
fv(gs /* ERROR "cannot pass" */ ())
fv(gs /* ERROR "cannot pass" */ ()...)
@ -448,7 +448,7 @@ func _calls() {
t.fm(1, 2.0, x)
t.fm(s /* ERROR "cannot pass" */ )
t.fm(g1())
t.fm(1, s /* ERROR "can only use ... with matching parameter" */ ...)
t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
t.fm(gs /* ERROR "cannot pass" */ ())
t.fm(gs /* ERROR "cannot pass" */ ()...)
@ -456,7 +456,7 @@ func _calls() {
T.fm(t, 1, 2.0, x)
T.fm(t, s /* ERROR "cannot pass" */ )
T.fm(t, g1())
T.fm(t, 1, s /* ERROR "can only use ... with matching parameter" */ ...)
T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
T.fm(t, gs /* ERROR "cannot pass" */ ())
T.fm(t, gs /* ERROR "cannot pass" */ ()...)
@ -465,7 +465,7 @@ func _calls() {
i.fm(1, 2.0, x)
i.fm(s /* ERROR "cannot pass" */ )
i.fm(g1())
i.fm(1, s /* ERROR "can only use ... with matching parameter" */ ...)
i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
i.fm(gs /* ERROR "cannot pass" */ ())
i.fm(gs /* ERROR "cannot pass" */ ()...)

View File

@ -41,3 +41,33 @@ func issue9182() {
// no error for composite literal based on unknown type
_ = Point{x: 1, y: 2}
}
func f0() (a []int) { return }
func f1() (a []int, b int) { return }
func f2() (a, b []int) { return }
func append_([]int, ...int) {}
func issue9473(a []int, b ...int) {
// variadic builtin function
_ = append(f0())
_ = append(f0(), f0()...)
_ = append(f1())
_ = append(f2 /* ERROR cannot pass argument */ ())
_ = append(f2()... /* ERROR cannot use ... */ )
_ = append(f0(), f1 /* ERROR 2-valued expression */ ())
_ = append(f0(), f2 /* ERROR 2-valued expression */ ())
_ = append(f0(), f1()... /* ERROR cannot use ... */ )
_ = append(f0(), f2()... /* ERROR cannot use ... */ )
// variadic user-defined function
append_(f0())
append_(f0(), f0()...)
append_(f1())
append_(f2 /* ERROR cannot pass argument */ ())
append_(f2()... /* ERROR cannot use ... */ )
append_(f0(), f1 /* ERROR 2-valued expression */ ())
append_(f0(), f2 /* ERROR 2-valued expression */ ())
append_(f0(), f1()... /* ERROR cannot use */ )
append_(f0(), f2()... /* ERROR cannot use */ )
}