mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/compile: restore original assignment error messages
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>
This commit is contained in:
parent
2fc7697da4
commit
0626ac064d
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
77
test/fixedbugs/issue48558.go
Normal file
77
test/fixedbugs/issue48558.go
Normal file
@ -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"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user