Commit 3f08151e authored by Robert Griesemer's avatar Robert Griesemer

go/types: cleanup handling of multi-valued expressions

- more uniform error messages
- removed unused code

Change-Id: I625d5c2e51a543450ad091f97cec538023ddb1dd
Reviewed-on: https://go-review.googlesource.com/14692Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent 712bae04
...@@ -19,6 +19,8 @@ import ( ...@@ -19,6 +19,8 @@ import (
// If the result is false and a non-nil reason is provided, it may be set // If the result is false and a non-nil reason is provided, it may be set
// to a more detailed explanation of the failure (result != ""). // to a more detailed explanation of the failure (result != "").
func (check *Checker) assignment(x *operand, T Type, reason *string) bool { func (check *Checker) assignment(x *operand, T Type, reason *string) bool {
check.singleValue(x)
switch x.mode { switch x.mode {
case invalid: case invalid:
return true // error reported before return true // error reported before
...@@ -28,17 +30,6 @@ func (check *Checker) assignment(x *operand, T Type, reason *string) bool { ...@@ -28,17 +30,6 @@ func (check *Checker) assignment(x *operand, T Type, reason *string) bool {
unreachable() unreachable()
} }
// x must be a single value
// (tuple types are never named - no need for underlying type)
// TODO(gri) We may be able to get rid of this check now that
// we check for single-valued expressions more rigorously.
if t, _ := x.typ.(*Tuple); t != nil {
assert(t.Len() > 1)
check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
x.mode = invalid
return false
}
if isUntyped(x.typ) { if isUntyped(x.typ) {
target := T target := T
// spec: "If an untyped constant is assigned to a variable of interface // spec: "If an untyped constant is assigned to a variable of interface
......
...@@ -181,14 +181,14 @@ func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) { ...@@ -181,14 +181,14 @@ func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) { func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
if call.Ellipsis.IsValid() { if call.Ellipsis.IsValid() {
// last argument is of the form x... // last argument is of the form x...
if len(call.Args) == 1 && n > 1 { if !sig.variadic {
// f()... is not permitted if f() is multi-valued check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
check.useGetter(arg, n) check.useGetter(arg, n)
return return
} }
if !sig.variadic { if len(call.Args) == 1 && n > 1 {
check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun) // f()... is not permitted if f() is multi-valued
check.errorf(call.Ellipsis, "cannot use ... with %d-valued %s", n, call.Args[0])
check.useGetter(arg, n) check.useGetter(arg, n)
return return
} }
...@@ -221,6 +221,11 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, ...@@ -221,6 +221,11 @@ 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. // argument checks passing of argument x to the i'th parameter of the given signature.
// If ellipsis is valid, the argument is followed by ... at that position in the call. // 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) { func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
check.singleValue(x)
if x.mode == invalid {
return
}
n := sig.params.Len() n := sig.params.Len()
// determine parameter type // determine parameter type
...@@ -241,18 +246,12 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token ...@@ -241,18 +246,12 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token
} }
if ellipsis.IsValid() { if ellipsis.IsValid() {
// argument is of the form x... // argument is of the form x... and x is single-valued
if i != n-1 { if i != n-1 {
check.errorf(ellipsis, "can only use ... with matching parameter") check.errorf(ellipsis, "can only use ... with matching parameter")
return return
} }
switch t := x.typ.Underlying().(type) { if _, ok := x.typ.Underlying().(*Slice); !ok {
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) check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
return return
} }
......
...@@ -1455,9 +1455,10 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, ...@@ -1455,9 +1455,10 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface,
func (check *Checker) singleValue(x *operand) { func (check *Checker) singleValue(x *operand) {
if x.mode == value { if x.mode == value {
// tuple types are never named - no need for Underlying() below // tuple types are never named - no need for underlying type below
if t, ok := x.typ.(*Tuple); ok && t.Len() != 1 { if t, ok := x.typ.(*Tuple); ok {
check.errorf(x.pos(), "%d-valued %s in single-value context", t.Len(), x) assert(t.Len() != 1)
check.errorf(x.pos(), "%d-valued %s where single value is expected", t.Len(), x)
x.mode = invalid x.mode = invalid
} }
} }
......
...@@ -524,7 +524,7 @@ func _calls() { ...@@ -524,7 +524,7 @@ func _calls() {
fi(1, 2.0, x, 3.14, "foo") fi(1, 2.0, x, 3.14, "foo")
fi(g2()) fi(g2())
fi(0, g2) fi(0, g2)
fi(0, g2 /* ERROR "2-valued expression" */ ()) fi(0, g2 /* ERROR "2-valued g2" */ ())
} }
func issue6344() { func issue6344() {
......
...@@ -54,10 +54,10 @@ func issue9473(a []int, b ...int) { ...@@ -54,10 +54,10 @@ func issue9473(a []int, b ...int) {
_ = append(f1()) _ = append(f1())
_ = append(f2 /* ERROR cannot pass argument */ ()) _ = append(f2 /* ERROR cannot pass argument */ ())
_ = append(f2()... /* ERROR cannot use ... */ ) _ = append(f2()... /* ERROR cannot use ... */ )
_ = append(f0(), f1 /* ERROR 2-valued expression */ ()) _ = append(f0(), f1 /* ERROR 2-valued f1 */ ())
_ = append(f0(), f2 /* ERROR 2-valued expression */ ()) _ = append(f0(), f2 /* ERROR 2-valued f2 */ ())
_ = append(f0(), f1()... /* ERROR cannot use ... */ ) _ = append(f0(), f1 /* ERROR 2-valued f1 */ ()...)
_ = append(f0(), f2()... /* ERROR cannot use ... */ ) _ = append(f0(), f2 /* ERROR 2-valued f2 */ ()...)
// variadic user-defined function // variadic user-defined function
append_(f0()) append_(f0())
...@@ -65,10 +65,10 @@ func issue9473(a []int, b ...int) { ...@@ -65,10 +65,10 @@ func issue9473(a []int, b ...int) {
append_(f1()) append_(f1())
append_(f2 /* ERROR cannot pass argument */ ()) append_(f2 /* ERROR cannot pass argument */ ())
append_(f2()... /* ERROR cannot use ... */ ) append_(f2()... /* ERROR cannot use ... */ )
append_(f0(), f1 /* ERROR 2-valued expression */ ()) append_(f0(), f1 /* ERROR 2-valued f1 */ ())
append_(f0(), f2 /* ERROR 2-valued expression */ ()) append_(f0(), f2 /* ERROR 2-valued f2 */ ())
append_(f0(), f1()... /* ERROR cannot use */ ) append_(f0(), f1 /* ERROR 2-valued f1 */ ()...)
append_(f0(), f2()... /* ERROR cannot use */ ) append_(f0(), f2 /* ERROR 2-valued f2 */ ()...)
} }
// Check that embedding a non-interface type in an interface results in a good error message. // Check that embedding a non-interface type in an interface results in a good error message.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment