]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: restore original assignment error messages
authorRobert Griesemer <gri@golang.org>
Thu, 23 Sep 2021 00:08:00 +0000 (17:08 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 23 Sep 2021 19:41:41 +0000 (19:41 +0000)
When used with the compiler, types2 will report assignment error
messages that closely match what the compiler type checker (types1)
produces.

Also, mark lhs variables as used in invalid variable initializations
to avoid a class of follow-on errors.

Fixes #48558.

Change-Id: I92d1de006c66b3a2364bb1bea773a312963afe75
Reviewed-on: https://go-review.googlesource.com/c/go/+/351669
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/expr.go
test/fixedbugs/issue19323.go
test/fixedbugs/issue26616.go
test/fixedbugs/issue27595.go
test/fixedbugs/issue48558.go [new file with mode: 0644]

index 29d63cf819af36582296c47e0debb49fc931591a..a1847b21ca98bc1f6b0af00cd692ebe38d18810f 100644 (file)
@@ -6,7 +6,10 @@
 
 package types2
 
-import "cmd/compile/internal/syntax"
+import (
+       "cmd/compile/internal/syntax"
+       "fmt"
+)
 
 // assignment reports whether x can be assigned to a variable of type T,
 // if necessary by attempting to convert untyped values to the appropriate
@@ -236,6 +239,28 @@ func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
        return x.typ
 }
 
+func (check *Checker) assignError(rhs []syntax.Expr, nvars, nvals int) {
+       measure := func(x int, unit string) string {
+               s := fmt.Sprintf("%d %s", x, unit)
+               if x != 1 {
+                       s += "s"
+               }
+               return s
+       }
+
+       vars := measure(nvars, "variable")
+       vals := measure(nvals, "value")
+       rhs0 := rhs[0]
+
+       if len(rhs) == 1 {
+               if call, _ := unparen(rhs0).(*syntax.CallExpr); call != nil {
+                       check.errorf(rhs0, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals)
+                       return
+               }
+       }
+       check.errorf(rhs0, "assignment mismatch: %s but %s", vars, vals)
+}
+
 // If returnPos is valid, initVars is called to type-check the assignment of
 // return expressions, and returnPos is the position of the return statement.
 func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syntax.Pos) {
@@ -244,6 +269,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syn
        if len(lhs) != len(rhs) {
                // invalidate lhs
                for _, obj := range lhs {
+                       obj.used = true // avoid declared but not used errors
                        if obj.typ == nil {
                                obj.typ = Typ[Invalid]
                        }
@@ -258,7 +284,11 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnPos syn
                        check.errorf(returnPos, "wrong number of return values (want %d, got %d)", len(lhs), len(rhs))
                        return
                }
-               check.errorf(rhs[0], "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+               if check.conf.CompilerErrorMessages {
+                       check.assignError(orig_rhs, len(lhs), len(rhs))
+               } else {
+                       check.errorf(rhs[0], "cannot initialize %d variables with %d values", len(lhs), len(rhs))
+               }
                return
        }
 
@@ -292,7 +322,11 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
                                return
                        }
                }
-               check.errorf(rhs[0], "cannot assign %d values to %d variables", len(rhs), len(lhs))
+               if check.conf.CompilerErrorMessages {
+                       check.assignError(orig_rhs, len(lhs), len(rhs))
+               } else {
+                       check.errorf(rhs[0], "cannot assign %d values to %d variables", len(rhs), len(lhs))
+               }
                return
        }
 
index 99204762bc8ddac3296341f2d812e55f87ab9326..12b7b6cd9f557414bca71860ed9cbeedae69559d 100644 (file)
@@ -1689,7 +1689,11 @@ func (check *Checker) singleValue(x *operand) {
                // 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, "%d-valued %s where single value is expected", t.Len(), x)
+                       if check.conf.CompilerErrorMessages {
+                               check.errorf(x, "multiple-value %s in single-value context", x)
+                       } else {
+                               check.errorf(x, "%d-valued %s where single value is expected", t.Len(), x)
+                       }
                        x.mode = invalid
                }
        }
index 77cac3ee16a230119167bc51d2806225b87f3d48..5db0a48a345faf5a25247ed1ac46b2fd4f8a50b6 100644 (file)
@@ -15,5 +15,5 @@ func f() {
 func g2() ([]byte, []byte) { return nil, nil }
 
 func f2() {
-       g2()[:] // ERROR "multiple-value g2.. in single-value context|attempt to slice object that is not|2\-valued g"
+       g2()[:] // ERROR "multiple-value g2.* in single-value context|attempt to slice object that is not|2\-valued g"
 }
index d5210e87b0f5af9d9183dbd7335f6ece002e6689..edf88d489ecc666b93e5bc8c1fc40d5140b1de71 100644 (file)
@@ -6,11 +6,11 @@
 
 package p
 
-var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+var x int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
 
 func f() {
-       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
-       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|3\-valued"
+       var _ int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
+       var a int = three() // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|multiple-value "
        a = three()         // ERROR "assignment mismatch: 1 variable but three returns 3 values|multiple-value function call in single-value context|cannot assign"
        b := three()        // ERROR "assignment mismatch: 1 variable but three returns 3 values|single variable set to multiple-value|multiple-value function call in single-value context|cannot initialize"
        _, _ = a, b
index 2fc0eb2a58ea17a7987ee0bf478c8097ab735731..86fb6384cdb5b48c99028db2e5fd1b60703b0ca8 100644 (file)
@@ -6,7 +6,7 @@
 
 package main
 
-var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|2\-valued"
+var a = twoResults()       // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|multiple-value twoResults\(\) .*in single-value context"
 var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values|cannot initialize"
 var e, f = oneResult()     // ERROR "assignment mismatch: 2 variables but oneResult returns 1 value|cannot initialize"
 
diff --git a/test/fixedbugs/issue48558.go b/test/fixedbugs/issue48558.go
new file mode 100644 (file)
index 0000000..9ab56d9
--- /dev/null
@@ -0,0 +1,77 @@
+// errorcheck
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func _(a, b, c int) {
+       _ = a
+       _ = a, b    // ERROR "assignment mismatch: 1 variable but 2 values"
+       _ = a, b, c // ERROR "assignment mismatch: 1 variable but 3 values"
+
+       _, _ = a // ERROR "assignment mismatch: 2 variables but 1 value"
+       _, _ = a, b
+       _, _ = a, b, c // ERROR "assignment mismatch: 2 variables but 3 values"
+
+       _, _, _ = a    // ERROR "assignment mismatch: 3 variables but 1 value"
+       _, _, _ = a, b // ERROR "assignment mismatch: 3 variables but 2 values"
+       _, _, _ = a, b, c
+}
+
+func f1() int
+func f2() (int, int)
+func f3() (int, int, int)
+
+func _() {
+       _ = f1()
+       _ = f2() // ERROR "assignment mismatch: 1 variable but f2 returns 2 values"
+       _ = f3() // ERROR "assignment mismatch: 1 variable but f3 returns 3 values"
+
+       _, _ = f1() // ERROR "assignment mismatch: 2 variables but f1 returns 1 value"
+       _, _ = f2()
+       _, _ = f3() // ERROR "assignment mismatch: 2 variables but f3 returns 3 values"
+
+       _, _, _ = f1() // ERROR "assignment mismatch: 3 variables but f1 returns 1 value"
+       _, _, _ = f2() // ERROR "assignment mismatch: 3 variables but f2 returns 2 values"
+       _, _, _ = f3()
+
+       // test just a few := cases as they use the same code as the = case
+       a1 := f3()         // ERROR "assignment mismatch: 1 variable but f3 returns 3 values"
+       a2, b2 := f1()     // ERROR "assignment mismatch: 2 variables but f1 returns 1 value"
+       a3, b3, c3 := f2() // ERROR "assignment mismatch: 3 variables but f2 returns 2 values"
+}
+
+type T struct{}
+
+func (T) f1() int
+func (T) f2() (int, int)
+func (T) f3() (int, int, int)
+
+func _(x T) {
+       _ = x.f1()
+       _ = x.f2() // ERROR "assignment mismatch: 1 variable but .\.f2 returns 2 values"
+       _ = x.f3() // ERROR "assignment mismatch: 1 variable but .\.f3 returns 3 values"
+
+       _, _ = x.f1() // ERROR "assignment mismatch: 2 variables but .\.f1 returns 1 value"
+       _, _ = x.f2()
+       _, _ = x.f3() // ERROR "assignment mismatch: 2 variables but .\.f3 returns 3 values"
+
+       _, _, _ = x.f1() // ERROR "assignment mismatch: 3 variables but .\.f1 returns 1 value"
+       _, _, _ = x.f2() // ERROR "assignment mismatch: 3 variables but .\.f2 returns 2 values"
+       _, _, _ = x.f3()
+
+       // test just a few := cases as they use the same code as the = case
+       a1 := x.f3()         // ERROR "assignment mismatch: 1 variable but .\.f3 returns 3 values"
+       a2, b2 := x.f1()     // ERROR "assignment mismatch: 2 variables but .\.f1 returns 1 value"
+       a3, b3, c3 := x.f2() // ERROR "assignment mismatch: 3 variables but .\.f2 returns 2 values"
+}
+
+// some one-off cases
+func _() {
+       _ = (f2)
+       _ = f1(), 2         // ERROR "assignment mismatch: 1 variable but 2 values"
+       _, _ = (f1()), f2() // ERROR "multiple-value f2\(\) .*in single-value context"
+       _, _, _ = f3(), 3   // ERROR "assignment mismatch: 3 variables but 2 values|multiple-value f3\(\) .*in single-value context"
+}