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/14692
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 240cea2..a906252 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -19,6 +19,8 @@
 // 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 != "").
 func (check *Checker) assignment(x *operand, T Type, reason *string) bool {
+	check.singleValue(x)
+
 	switch x.mode {
 	case invalid:
 		return true // error reported before
@@ -28,17 +30,6 @@
 		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) {
 		target := T
 		// spec: "If an untyped constant is assigned to a variable of interface
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 14c94de..4ce0a6b 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -181,14 +181,14 @@
 func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
 	if call.Ellipsis.IsValid() {
 		// last argument is of the form x...
-		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])
+		if !sig.variadic {
+			check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
 			check.useGetter(arg, n)
 			return
 		}
-		if !sig.variadic {
-			check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+		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 %s", n, call.Args[0])
 			check.useGetter(arg, n)
 			return
 		}
@@ -221,6 +221,11 @@
 // 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.
 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()
 
 	// determine parameter type
@@ -241,18 +246,12 @@
 	}
 
 	if ellipsis.IsValid() {
-		// argument is of the form x...
+		// argument is of the form x... and x is single-valued
 		if i != n-1 {
 			check.errorf(ellipsis, "can only use ... with matching parameter")
 			return
 		}
-		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:
+		if _, ok := x.typ.Underlying().(*Slice); !ok {
 			check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
 			return
 		}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index bbdaf9b..0f5712b 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -1455,9 +1455,10 @@
 
 func (check *Checker) singleValue(x *operand) {
 	if x.mode == value {
-		// tuple types are never named - no need for Underlying() below
-		if t, ok := x.typ.(*Tuple); ok && t.Len() != 1 {
-			check.errorf(x.pos(), "%d-valued %s in single-value context", t.Len(), x)
+		// tuple types are never named - no need for underlying type below
+		if t, ok := x.typ.(*Tuple); ok {
+			assert(t.Len() != 1)
+			check.errorf(x.pos(), "%d-valued %s where single value is expected", t.Len(), x)
 			x.mode = invalid
 		}
 	}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index 5772095..1b02c9a 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -524,7 +524,7 @@
 	fi(1, 2.0, x, 3.14, "foo")
 	fi(g2())
 	fi(0, g2)
-	fi(0, g2 /* ERROR "2-valued expression" */ ())
+	fi(0, g2 /* ERROR "2-valued g2" */ ())
 }
 
 func issue6344() {
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
index b108a2c..a2db9d7 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -54,10 +54,10 @@
 	_ = 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 ... */ )
+	_ = append(f0(), f1 /* ERROR 2-valued f1 */ ())
+	_ = append(f0(), f2 /* ERROR 2-valued f2 */ ())
+	_ = append(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+	_ = append(f0(), f2 /* ERROR 2-valued f2 */ ()...)
 
 	// variadic user-defined function
 	append_(f0())
@@ -65,10 +65,10 @@
 	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 */ )
+	append_(f0(), f1 /* ERROR 2-valued f1 */ ())
+	append_(f0(), f2 /* ERROR 2-valued f2 */ ())
+	append_(f0(), f1 /* ERROR 2-valued f1 */ ()...)
+	append_(f0(), f2 /* ERROR 2-valued f2 */ ()...)
 }
 
 // Check that embedding a non-interface type in an interface results in a good error message.