From: Robert Griesemer Date: Thu, 23 Mar 2023 03:57:52 +0000 (-0700) Subject: go/types, types2: don't report assignment mismatch errors if there are other errors X-Git-Tag: go1.21rc1~1122 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=91a40f43b629ac9237967f3faf0733de268ea652;p=gostls13.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 Reviewed-by: Robert Griesemer TryBot-Result: Gopher Robot Run-TryBot: Robert Griesemer Auto-Submit: Robert Griesemer --- diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index adef1e8d99..3ca6bebd31 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -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 // resulting in 2 or more values; otherwise we have an assignment mismatch. if r != 1 { - if returnStmt != nil { - rhs := check.exprList(orig_rhs) - check.returnError(returnStmt, lhs, rhs) - } else { - check.assignError(orig_rhs, l, r) + // Only report a mismatch error if there are no other errors on the rhs. + if check.use(orig_rhs...) { + if returnStmt != nil { + rhs := check.exprList(orig_rhs) + check.returnError(returnStmt, lhs, rhs) + } else { + check.assignError(orig_rhs, l, r) + } } // ensure that LHS variables have a type for _, v := range lhs { @@ -372,7 +375,6 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy v.typ = Typ[Invalid] } } - check.use(orig_rhs...) 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. - // Only report a mismatch error if there was no error - // on the rhs. + // Only report a mismatch error if there are no other errors on the rhs. if rhs[0].mode != invalid { if returnStmt != nil { 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 // resulting in 2 or more values; otherwise we have an assignment mismatch. if r != 1 { - check.assignError(orig_rhs, l, r) - check.useLHS(lhs...) - check.use(orig_rhs...) + // Only report a mismatch error if there are no other errors on the lhs or rhs. + okLHS := check.useLHS(lhs...) + okRHS := check.use(orig_rhs...) + if okLHS && okRHS { + check.assignError(orig_rhs, l, r) + } return } @@ -451,8 +455,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []syntax.Expr) { } // In all other cases we have an assignment mismatch. - // Only report a mismatch error if there was no error - // on the rhs. + // Only report a mismatch error if there are no other errors on the rhs. if rhs[0].mode != invalid { check.assignError(orig_rhs, l, r) } diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 1400aba883..72608dea26 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -699,23 +699,27 @@ Error: // Useful to make sure expressions are evaluated // (and variables are "used") in the presence of // other errors. Arguments may be nil. -func (check *Checker) use(args ...syntax.Expr) { - for _, e := range args { - check.use1(e, false) - } -} +// Reports if all arguments evaluated without error. +func (check *Checker) use(args ...syntax.Expr) bool { return check.useN(args, false) } // useLHS is like use, but doesn't "use" top-level identifiers. // It should be called instead of use if the arguments are // 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 { - 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 + x.mode = value // anything but invalid switch n := unparen(e).(type) { case nil: // nothing to do @@ -745,10 +749,9 @@ func (check *Checker) use1(e syntax.Expr, lhs bool) { v.used = v_used // restore v.used } case *syntax.ListExpr: - for _, e := range n.ElemList { - check.use1(e, lhs) - } + return check.useN(n.ElemList, lhs) default: check.rawExpr(&x, e, nil, true) } + return x.mode != invalid } diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go index 26de0a093a..a73e4515bc 100644 --- a/src/go/types/assignments.go +++ b/src/go/types/assignments.go @@ -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 // resulting in 2 or more values; otherwise we have an assignment mismatch. if r != 1 { - if returnStmt != nil { - rhs := check.exprList(orig_rhs) - check.returnError(returnStmt, lhs, rhs) - } else { - check.assignError(orig_rhs, l, r) + // Only report a mismatch error if there are no other errors on the rhs. + if check.use(orig_rhs...) { + if returnStmt != nil { + rhs := check.exprList(orig_rhs) + check.returnError(returnStmt, lhs, rhs) + } else { + check.assignError(orig_rhs, l, r) + } } // ensure that LHS variables have a type 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] } } - check.use(orig_rhs...) 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. - // Only report a mismatch error if there was no error - // on the rhs. + // Only report a mismatch error if there are no other errors on the rhs. if rhs[0].mode != invalid { if returnStmt != nil { 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 // resulting in 2 or more values; otherwise we have an assignment mismatch. if r != 1 { - check.assignError(orig_rhs, l, r) - check.useLHS(lhs...) - check.use(orig_rhs...) + // Only report a mismatch error if there are no other errors on the lhs or rhs. + okLHS := check.useLHS(lhs...) + okRHS := check.use(orig_rhs...) + if okLHS && okRHS { + check.assignError(orig_rhs, l, r) + } return } @@ -449,8 +453,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) { } // In all other cases we have an assignment mismatch. - // Only report a mismatch error if there was no error - // on the rhs. + // Only report a mismatch error if there are no other errors on the rhs. if rhs[0].mode != invalid { check.assignError(orig_rhs, l, r) } diff --git a/src/go/types/call.go b/src/go/types/call.go index f8aa261816..e5968c7cfc 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -746,23 +746,27 @@ Error: // Useful to make sure expressions are evaluated // (and variables are "used") in the presence of // other errors. Arguments may be nil. -func (check *Checker) use(args ...ast.Expr) { - for _, e := range args { - check.use1(e, false) - } -} +// Reports if all arguments evaluated without error. +func (check *Checker) use(args ...ast.Expr) bool { return check.useN(args, false) } // useLHS is like use, but doesn't "use" top-level identifiers. // It should be called instead of use if the arguments are // 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 { - 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 + x.mode = value // anything but invalid switch n := unparen(e).(type) { case nil: // nothing to do @@ -794,4 +798,5 @@ func (check *Checker) use1(e ast.Expr, lhs bool) { default: check.rawExpr(&x, e, nil, true) } + return x.mode != invalid } diff --git a/test/fixedbugs/issue19012.go b/test/fixedbugs/issue19012.go index c911a9a1d0..77b2236063 100644 --- a/test/fixedbugs/issue19012.go +++ b/test/fixedbugs/issue19012.go @@ -15,7 +15,7 @@ func f(x int, y uint) { 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 "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() {