mirror of https://github.com/golang/go.git
go/types, types2: don't report assignment mismatch errors if there are other errors
Change the Checker.use/useLHS functions to report if all "used" expressions evaluated without error. Use that information to control whether to report an assignment mismatch error or not. This will reduce the number of errors reported per assignment, where the assignment mismatch is only one of the errors. Change-Id: Ia0fc3203253b002e4e1d5759d8d5644999af6884 Reviewed-on: https://go-review.googlesource.com/c/go/+/478756 Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
a6f564c8e9
commit
91a40f43b6
|
|
@ -360,11 +360,14 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy
|
||||||
// If we don't have an n:n mapping, the rhs must be a single expression
|
// If we don't have an n:n mapping, the rhs must be a single expression
|
||||||
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
||||||
if r != 1 {
|
if r != 1 {
|
||||||
if returnStmt != nil {
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
rhs := check.exprList(orig_rhs)
|
if check.use(orig_rhs...) {
|
||||||
check.returnError(returnStmt, lhs, rhs)
|
if returnStmt != nil {
|
||||||
} else {
|
rhs := check.exprList(orig_rhs)
|
||||||
check.assignError(orig_rhs, l, r)
|
check.returnError(returnStmt, lhs, rhs)
|
||||||
|
} else {
|
||||||
|
check.assignError(orig_rhs, l, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ensure that LHS variables have a type
|
// ensure that LHS variables have a type
|
||||||
for _, v := range lhs {
|
for _, v := range lhs {
|
||||||
|
|
@ -372,7 +375,6 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy
|
||||||
v.typ = Typ[Invalid]
|
v.typ = Typ[Invalid]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check.use(orig_rhs...)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,8 +391,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all other cases we have an assignment mismatch.
|
// In all other cases we have an assignment mismatch.
|
||||||
// Only report a mismatch error if there was no error
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
// on the rhs.
|
|
||||||
if rhs[0].mode != invalid {
|
if rhs[0].mode != invalid {
|
||||||
if returnStmt != nil {
|
if returnStmt != nil {
|
||||||
check.returnError(returnStmt, lhs, rhs)
|
check.returnError(returnStmt, lhs, rhs)
|
||||||
|
|
@ -432,9 +433,12 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
|
||||||
// If we don't have an n:n mapping, the rhs must be a single expression
|
// If we don't have an n:n mapping, the rhs must be a single expression
|
||||||
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
||||||
if r != 1 {
|
if r != 1 {
|
||||||
check.assignError(orig_rhs, l, r)
|
// Only report a mismatch error if there are no other errors on the lhs or rhs.
|
||||||
check.useLHS(lhs...)
|
okLHS := check.useLHS(lhs...)
|
||||||
check.use(orig_rhs...)
|
okRHS := check.use(orig_rhs...)
|
||||||
|
if okLHS && okRHS {
|
||||||
|
check.assignError(orig_rhs, l, r)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -451,8 +455,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all other cases we have an assignment mismatch.
|
// In all other cases we have an assignment mismatch.
|
||||||
// Only report a mismatch error if there was no error
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
// on the rhs.
|
|
||||||
if rhs[0].mode != invalid {
|
if rhs[0].mode != invalid {
|
||||||
check.assignError(orig_rhs, l, r)
|
check.assignError(orig_rhs, l, r)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -699,23 +699,27 @@ Error:
|
||||||
// Useful to make sure expressions are evaluated
|
// Useful to make sure expressions are evaluated
|
||||||
// (and variables are "used") in the presence of
|
// (and variables are "used") in the presence of
|
||||||
// other errors. Arguments may be nil.
|
// other errors. Arguments may be nil.
|
||||||
func (check *Checker) use(args ...syntax.Expr) {
|
// Reports if all arguments evaluated without error.
|
||||||
for _, e := range args {
|
func (check *Checker) use(args ...syntax.Expr) bool { return check.useN(args, false) }
|
||||||
check.use1(e, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// useLHS is like use, but doesn't "use" top-level identifiers.
|
// useLHS is like use, but doesn't "use" top-level identifiers.
|
||||||
// It should be called instead of use if the arguments are
|
// It should be called instead of use if the arguments are
|
||||||
// expressions on the lhs of an assignment.
|
// expressions on the lhs of an assignment.
|
||||||
func (check *Checker) useLHS(args ...syntax.Expr) {
|
func (check *Checker) useLHS(args ...syntax.Expr) bool { return check.useN(args, true) }
|
||||||
|
|
||||||
|
func (check *Checker) useN(args []syntax.Expr, lhs bool) bool {
|
||||||
|
ok := true
|
||||||
for _, e := range args {
|
for _, e := range args {
|
||||||
check.use1(e, true)
|
if !check.use1(e, lhs) {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) use1(e syntax.Expr, lhs bool) {
|
func (check *Checker) use1(e syntax.Expr, lhs bool) bool {
|
||||||
var x operand
|
var x operand
|
||||||
|
x.mode = value // anything but invalid
|
||||||
switch n := unparen(e).(type) {
|
switch n := unparen(e).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
|
@ -745,10 +749,9 @@ func (check *Checker) use1(e syntax.Expr, lhs bool) {
|
||||||
v.used = v_used // restore v.used
|
v.used = v_used // restore v.used
|
||||||
}
|
}
|
||||||
case *syntax.ListExpr:
|
case *syntax.ListExpr:
|
||||||
for _, e := range n.ElemList {
|
return check.useN(n.ElemList, lhs)
|
||||||
check.use1(e, lhs)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
check.rawExpr(&x, e, nil, true)
|
check.rawExpr(&x, e, nil, true)
|
||||||
}
|
}
|
||||||
|
return x.mode != invalid
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,11 +358,14 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S
|
||||||
// If we don't have an n:n mapping, the rhs must be a single expression
|
// If we don't have an n:n mapping, the rhs must be a single expression
|
||||||
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
||||||
if r != 1 {
|
if r != 1 {
|
||||||
if returnStmt != nil {
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
rhs := check.exprList(orig_rhs)
|
if check.use(orig_rhs...) {
|
||||||
check.returnError(returnStmt, lhs, rhs)
|
if returnStmt != nil {
|
||||||
} else {
|
rhs := check.exprList(orig_rhs)
|
||||||
check.assignError(orig_rhs, l, r)
|
check.returnError(returnStmt, lhs, rhs)
|
||||||
|
} else {
|
||||||
|
check.assignError(orig_rhs, l, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// ensure that LHS variables have a type
|
// ensure that LHS variables have a type
|
||||||
for _, v := range lhs {
|
for _, v := range lhs {
|
||||||
|
|
@ -370,7 +373,6 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S
|
||||||
v.typ = Typ[Invalid]
|
v.typ = Typ[Invalid]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check.use(orig_rhs...)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,8 +389,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all other cases we have an assignment mismatch.
|
// In all other cases we have an assignment mismatch.
|
||||||
// Only report a mismatch error if there was no error
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
// on the rhs.
|
|
||||||
if rhs[0].mode != invalid {
|
if rhs[0].mode != invalid {
|
||||||
if returnStmt != nil {
|
if returnStmt != nil {
|
||||||
check.returnError(returnStmt, lhs, rhs)
|
check.returnError(returnStmt, lhs, rhs)
|
||||||
|
|
@ -430,9 +431,12 @@ func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
|
||||||
// If we don't have an n:n mapping, the rhs must be a single expression
|
// If we don't have an n:n mapping, the rhs must be a single expression
|
||||||
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
// resulting in 2 or more values; otherwise we have an assignment mismatch.
|
||||||
if r != 1 {
|
if r != 1 {
|
||||||
check.assignError(orig_rhs, l, r)
|
// Only report a mismatch error if there are no other errors on the lhs or rhs.
|
||||||
check.useLHS(lhs...)
|
okLHS := check.useLHS(lhs...)
|
||||||
check.use(orig_rhs...)
|
okRHS := check.use(orig_rhs...)
|
||||||
|
if okLHS && okRHS {
|
||||||
|
check.assignError(orig_rhs, l, r)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -449,8 +453,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// In all other cases we have an assignment mismatch.
|
// In all other cases we have an assignment mismatch.
|
||||||
// Only report a mismatch error if there was no error
|
// Only report a mismatch error if there are no other errors on the rhs.
|
||||||
// on the rhs.
|
|
||||||
if rhs[0].mode != invalid {
|
if rhs[0].mode != invalid {
|
||||||
check.assignError(orig_rhs, l, r)
|
check.assignError(orig_rhs, l, r)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -746,23 +746,27 @@ Error:
|
||||||
// Useful to make sure expressions are evaluated
|
// Useful to make sure expressions are evaluated
|
||||||
// (and variables are "used") in the presence of
|
// (and variables are "used") in the presence of
|
||||||
// other errors. Arguments may be nil.
|
// other errors. Arguments may be nil.
|
||||||
func (check *Checker) use(args ...ast.Expr) {
|
// Reports if all arguments evaluated without error.
|
||||||
for _, e := range args {
|
func (check *Checker) use(args ...ast.Expr) bool { return check.useN(args, false) }
|
||||||
check.use1(e, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// useLHS is like use, but doesn't "use" top-level identifiers.
|
// useLHS is like use, but doesn't "use" top-level identifiers.
|
||||||
// It should be called instead of use if the arguments are
|
// It should be called instead of use if the arguments are
|
||||||
// expressions on the lhs of an assignment.
|
// expressions on the lhs of an assignment.
|
||||||
func (check *Checker) useLHS(args ...ast.Expr) {
|
func (check *Checker) useLHS(args ...ast.Expr) bool { return check.useN(args, true) }
|
||||||
|
|
||||||
|
func (check *Checker) useN(args []ast.Expr, lhs bool) bool {
|
||||||
|
ok := true
|
||||||
for _, e := range args {
|
for _, e := range args {
|
||||||
check.use1(e, true)
|
if !check.use1(e, lhs) {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *Checker) use1(e ast.Expr, lhs bool) {
|
func (check *Checker) use1(e ast.Expr, lhs bool) bool {
|
||||||
var x operand
|
var x operand
|
||||||
|
x.mode = value // anything but invalid
|
||||||
switch n := unparen(e).(type) {
|
switch n := unparen(e).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
|
@ -794,4 +798,5 @@ func (check *Checker) use1(e ast.Expr, lhs bool) {
|
||||||
default:
|
default:
|
||||||
check.rawExpr(&x, e, nil, true)
|
check.rawExpr(&x, e, nil, true)
|
||||||
}
|
}
|
||||||
|
return x.mode != invalid
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ func f(x int, y uint) {
|
||||||
if true {
|
if true {
|
||||||
return "a" > 10 // ERROR "^too many arguments to return$|return with value in function with no return|no result values expected|mismatched types"
|
return "a" > 10 // ERROR "^too many arguments to return$|return with value in function with no return|no result values expected|mismatched types"
|
||||||
}
|
}
|
||||||
return "gopher" == true, 10 // ERROR "^too many arguments to return$|return with value in function with no return|no result values expected|mismatched types" "too many return values"
|
return "gopher" == true, 10 // ERROR "^too many arguments to return$|return with value in function with no return|no result values expected|mismatched types"
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue