]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: better error message when using multi-valued expressions in single-value...
authorRobert Griesemer <gri@golang.org>
Thu, 17 Sep 2015 00:52:12 +0000 (17:52 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 18 Sep 2015 17:00:11 +0000 (17:00 +0000)
Also: Added initial set of (missing and/or spread out) tests for binary operations.

Fixes #11896.

Change-Id: I037436d8318c18f9758b435eca2d45b3bdd17ef8
Reviewed-on: https://go-review.googlesource.com/14660
Reviewed-by: Alan Donovan <adonovan@google.com>
src/go/types/assignments.go
src/go/types/builtins.go
src/go/types/call.go
src/go/types/expr.go
src/go/types/testdata/expr0.src
src/go/types/testdata/expr1.src
src/go/types/testdata/stmt0.src
src/go/types/testdata/vardecl.src

index 4231196b2ddf16c2409bf683b1d95aca82ce0b27..240cea24dbaffb12898427f46f44fa1d7d15bf21 100644 (file)
@@ -30,6 +30,8 @@ func (check *Checker) assignment(x *operand, T Type, reason *string) bool {
 
        // 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)
@@ -205,7 +207,7 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
 // return expressions, and returnPos is the position of the return statement.
 func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
        l := len(lhs)
-       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+       get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
        if get == nil || l != r {
                // invalidate lhs and use rhs
                for _, obj := range lhs {
@@ -244,7 +246,7 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
 
 func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
        l := len(lhs)
-       get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+       get, r, commaOk := unpack(func(x *operand, i int) { check.multiExpr(x, rhs[i]) }, len(rhs), l == 2)
        if get == nil {
                return // error reported by unpack
        }
index a879c8164db5e0c05eec2c207a7f9069ecf52ca1..be6c92982d390458b96e991502eb5c2556d30df6 100644 (file)
@@ -44,7 +44,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        switch id {
        default:
                // make argument getter
-               arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+               arg, nargs, _ = unpack(func(x *operand, i int) { check.multiExpr(x, call.Args[i]) }, nargs, false)
                if arg == nil {
                        return
                }
index c3ed0778e9500dcab611c10ea5fde94c85d4eb5f..14c94de21069b2c68af1b828c676c51c5085a0f8 100644 (file)
@@ -61,7 +61,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
                        return statement
                }
 
-               arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+               arg, n, _ := unpack(func(x *operand, i int) { check.multiExpr(x, e.Args[i]) }, len(e.Args), false)
                if arg == nil {
                        x.mode = invalid
                        x.expr = e
index 9d2331a1ad5d8db5ad526433ac3917cfe09c1da2..bbdaf9b3ce12f34f736d40589650fc2d517b9a41 100644 (file)
@@ -1453,23 +1453,40 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface,
        check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
 }
 
+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)
+                       x.mode = invalid
+               }
+       }
+}
+
 // expr typechecks expression e and initializes x with the expression value.
+// The result must be a single value.
 // If an error occurred, x.mode is set to invalid.
 //
 func (check *Checker) expr(x *operand, e ast.Expr) {
+       check.multiExpr(x, e)
+       check.singleValue(x)
+}
+
+// multiExpr is like expr but the result may be a multi-value.
+func (check *Checker) multiExpr(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
        var msg string
        switch x.mode {
        default:
                return
        case novalue:
-               msg = "used as value"
+               msg = "%s used as value"
        case builtin:
-               msg = "must be called"
+               msg = "%s must be called"
        case typexpr:
-               msg = "is not an expression"
+               msg = "%s is not an expression"
        }
-       check.errorf(x.pos(), "%s %s", x, msg)
+       check.errorf(x.pos(), msg, x)
        x.mode = invalid
 }
 
@@ -1480,18 +1497,19 @@ func (check *Checker) expr(x *operand, e ast.Expr) {
 func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
        assert(hint != nil)
        check.rawExpr(x, e, hint)
+       check.singleValue(x)
        var msg string
        switch x.mode {
        default:
                return
        case novalue:
-               msg = "used as value"
+               msg = "%s used as value"
        case builtin:
-               msg = "must be called"
+               msg = "%s must be called"
        case typexpr:
-               msg = "is not an expression"
+               msg = "%s is not an expression"
        }
-       check.errorf(x.pos(), "%s %s", x, msg)
+       check.errorf(x.pos(), msg, x)
        x.mode = invalid
 }
 
@@ -1500,6 +1518,7 @@ func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
 //
 func (check *Checker) exprOrType(x *operand, e ast.Expr) {
        check.rawExpr(x, e, nil)
+       check.singleValue(x)
        if x.mode == novalue {
                check.errorf(x.pos(), "%s used as value or type", x)
                x.mode = invalid
index 3120c6f0781aabf2be14fa926d225cef793ac93a..2a917c06e2f326f70bc659ef4207eb270b4379dc 100644 (file)
@@ -172,3 +172,9 @@ var (
        p3 P = &p2
 )
 
+func g() (a, b int) { return }
+
+func _() {
+       _ = -g /* ERROR 2-valued g */ ()
+       _ = <-g /* ERROR 2-valued g */ ()
+}
index 8ef0aed6d2ea16ed8d811338a04c1f68fab08751..eaaf610b03b54332469dd5524c4fdd7285146801 100644 (file)
@@ -5,3 +5,123 @@
 // binary expressions
 
 package expr1
+
+type mybool bool
+
+func _(x, y bool, z mybool) {
+       x = x || y
+       x = x || true
+       x = x || false
+       x = x && y
+       x = x && true
+       x = x && false
+
+       z = z /* ERROR mismatched types */ || y
+       z = z || true
+       z = z || false
+       z = z /* ERROR mismatched types */ && y
+       z = z && true
+       z = z && false
+}
+
+type myint int
+
+func _(x, y int, z myint) {
+       x = x + 1
+       x = x + 1.0
+       x = x + 1.1 // ERROR truncated to int
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x % y
+       x = x << y // ERROR must be unsigned integer
+       x = x >> y // ERROR must be unsigned integer
+
+       z = z + 1
+       z = z + 1.0
+       z = z + 1.1 // ERROR truncated to int
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z << y // ERROR must be unsigned integer
+       z = z >> y // ERROR must be unsigned integer
+}
+
+type myuint uint
+
+func _(x, y uint, z myuint) {
+       x = x + 1
+       x = x + - /* ERROR overflows uint */ 1
+       x = x + 1.0
+       x = x + 1.1 // ERROR truncated to uint
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x % y
+       x = x << y
+       x = x >> y
+
+       z = z + 1
+       z = x + - /* ERROR overflows uint */ 1
+       z = z + 1.0
+       z = z + 1.1 // ERROR truncated to uint
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z << y
+       z = z >> y
+}
+
+type myfloat64 float64
+
+func _(x, y float64, z myfloat64) {
+       x = x + 1
+       x = x + -1
+       x = x + 1.0
+       x = x + 1.1
+       x = x + y
+       x = x - y
+       x = x * y
+       x = x / y
+       x = x /* ERROR not defined */ % y
+       x = x /* ERROR operand x .* must be integer */ << y
+       x = x /* ERROR operand x .* must be integer */ >> y
+
+       z = z + 1
+       z = z + -1
+       z = z + 1.0
+       z = z + 1.1
+       z = z /* ERROR mismatched types */ + y
+       z = z /* ERROR mismatched types */ - y
+       z = z /* ERROR mismatched types */ * y
+       z = z /* ERROR mismatched types */ / y
+       z = z /* ERROR mismatched types */ % y
+       z = z /* ERROR operand z .* must be integer */ << y
+       z = z /* ERROR operand z .* must be integer */ >> y
+}
+
+type mystring string
+
+func _(x, y string, z mystring) {
+       x = x + "foo"
+       x = x /* ERROR not defined */ - "foo"
+       x = x + 1 // ERROR cannot convert
+       x = x + y
+       x = x /* ERROR not defined */ - y
+       x = x * 10 // ERROR cannot convert
+}
+
+func f() (a, b int) { return }
+
+func _(x int) {
+       _ = f /* ERROR 2-valued f */ () + 1
+       _ = x + f /* ERROR 2-valued f */ ()
+       _ = f /* ERROR 2-valued f */ () + f
+       _ = f /* ERROR 2-valued f */ () + f /* ERROR 2-valued f */ ()
+}
index 80abbd1d96f67bda60f3a9543da69ac9c04dcdd1..52ed65c68bd22df5ec4461dbe308c2c4992fc48b 100644 (file)
@@ -631,14 +631,14 @@ func issue11667() {
 
 func issue11687() {
        f := func() (_, _ int) { return }
-       switch f /* ERROR "2-valued expression" */ () {
+       switch f /* ERROR "2-valued f" */ () {
        }
        var x int
-       switch f /* ERROR "2-valued expression" */ () {
+       switch f /* ERROR "2-valued f" */ () {
        case x:
        }
        switch x {
-       case f /* ERROR "cannot compare" */ (): // TODO(gri) better error message (issue 11896)
+       case f /* ERROR "2-valued f" */ ():
        }
 }
 
index fb6b5f78382965edc1b369cbd4a56e31a032d288..00825371f2c7569d6959983921b6daabb0666011 100644 (file)
@@ -31,7 +31,7 @@ var _ = 1, 2 /* ERROR "extra init expr 2" */
 var _, _ = 1 /* ERROR "assignment count mismatch" */
 var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
 
-var _ = g /* ERROR "2-valued expr" */ ()
+var _ = g /* ERROR "2-valued g" */ ()
 var _, _ = g()
 var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
 
@@ -50,7 +50,7 @@ var (
        _, _ = 1 /* ERROR "assignment count mismatch" */
        _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
 
-       _ = g /* ERROR "2-valued expr" */ ()
+       _ = g /* ERROR "2-valued g" */ ()
        _, _ = g()
        _, _, _ = g /* ERROR "assignment count mismatch" */ ()