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
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) {
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]
}
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
}
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
}
// 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
}
}
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"
}
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
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"
--- /dev/null
+// 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"
+}