diff --git a/go/types/builtins.go b/go/types/builtins.go index 97ccf4c6..8447f0b6 100644 --- a/go/types/builtins.go +++ b/go/types/builtins.go @@ -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 diff --git a/go/types/call.go b/go/types/call.go index a392d910..5811a12b 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -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 } diff --git a/go/types/initorder.go b/go/types/initorder.go index 0fd567b2..2892cfa8 100644 --- a/go/types/initorder.go +++ b/go/types/initorder.go @@ -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) { diff --git a/go/types/testdata/builtins.src b/go/types/testdata/builtins.src index 8b405c3f..9eb551dc 100644 --- a/go/types/testdata/builtins.src +++ b/go/types/testdata/builtins.src @@ -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 diff --git a/go/types/testdata/expr3.src b/go/types/testdata/expr3.src index 50ae7c4c..c370ce34 100644 --- a/go/types/testdata/expr3.src +++ b/go/types/testdata/expr3.src @@ -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" */ ()...) diff --git a/go/types/testdata/issues.src b/go/types/testdata/issues.src index 417f06c5..d08e0fd8 100644 --- a/go/types/testdata/issues.src +++ b/go/types/testdata/issues.src @@ -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 */ ) +}