]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, go/types: restore 'too many return values' error for func with no results
authorRuss Cox <rsc@golang.org>
Tue, 18 Jan 2022 15:31:59 +0000 (10:31 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 18 Jan 2022 21:43:02 +0000 (21:43 +0000)
Currently the code handles the case of returning values from
a function with no result parameters as a special case.
Consider this input:

package p

func f0_2()            { return 1, 2 }
func f0_1()            { return 1 }
func f1_0() int        { return }
func f1_2() int        { return 1, 2 }
func f2_0() (int, int) { return }
func f2_1() (int, int) { return 1 }

The errors are:

x.go:3:33: no result values expected   <<<
x.go:4:33: no result values expected   <<<
x.go:5:26: not enough return values
have ()
want (int)
x.go:6:36: too many return values
have (number, number)
want (int)
x.go:7:26: not enough return values
have ()
want (int, int)
x.go:8:33: not enough return values
have (number)
want (int, int)

There are two problems with the current special case emitting the
errors on the marked line:

1. It calls them 'result values' instead of 'return values'.
2. It doesn't show the type being returned, which can be useful to programmers.

Using the general case solves both these problems,
so this CL removes the special case and calls the general case instead.

Now those two errors read:

x.go:3:33: too many return values
have (number, number)
want ()
x.go:4:33: too many return values
have (number)
want ()

Fixes #50653.

Change-Id: If6b47dcece14ed4febb3a2d3d78270d5be1cb24d
Reviewed-on: https://go-review.googlesource.com/c/go/+/379116
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/testdata/check/stmt0.src
src/cmd/compile/internal/types2/testdata/check/vardecl.src
src/go/types/stmt.go
src/go/types/testdata/check/stmt0.src
src/go/types/testdata/check/vardecl.src
test/fixedbugs/issue4215.go
test/fixedbugs/issue48834.go

index 98244cd5e979c6d2ac5f46606f56b424561b1474..b23d7aeef210c6503ef5be29b9bc454e543a249f 100644 (file)
@@ -474,30 +474,28 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
 
        case *syntax.ReturnStmt:
                res := check.sig.results
+               // Return with implicit results allowed for function with named results.
+               // (If one is named, all are named.)
                results := unpackExpr(s.Results)
-               if res.Len() > 0 {
-                       // function returns results
-                       // (if one, say the first, result parameter is named, all of them are named)
-                       if len(results) == 0 && res.vars[0].name != "" {
-                               // spec: "Implementation restriction: A compiler may disallow an empty expression
-                               // list in a "return" statement if a different entity (constant, type, or variable)
-                               // with the same name as a result parameter is in scope at the place of the return."
-                               for _, obj := range res.vars {
-                                       if alt := check.lookup(obj.name); alt != nil && alt != obj {
-                                               var err error_
-                                               err.errorf(s, "result parameter %s not in scope at return", obj.name)
-                                               err.errorf(alt, "inner declaration of %s", obj)
-                                               check.report(&err)
-                                               // ok to continue
-                                       }
+               if len(results) == 0 && res.Len() > 0 && res.vars[0].name != "" {
+                       // spec: "Implementation restriction: A compiler may disallow an empty expression
+                       // list in a "return" statement if a different entity (constant, type, or variable)
+                       // with the same name as a result parameter is in scope at the place of the return."
+                       for _, obj := range res.vars {
+                               if alt := check.lookup(obj.name); alt != nil && alt != obj {
+                                       var err error_
+                                       err.errorf(s, "result parameter %s not in scope at return", obj.name)
+                                       err.errorf(alt, "inner declaration of %s", obj)
+                                       check.report(&err)
+                                       // ok to continue
                                }
-                       } else {
-                               // return has results or result parameters are unnamed
-                               check.initVars(res.vars, results, s)
                        }
-               } else if len(results) > 0 {
-                       check.error(results[0], "no result values expected")
-                       check.use(results...)
+               } else {
+                       var lhs []*Var
+                       if res.Len() > 0 {
+                               lhs = res.vars
+                       }
+                       check.initVars(lhs, results, s)
                }
 
        case *syntax.BranchStmt:
index c4820c9f7fa0bc694f7f9dabcfa239163b542364..ed7ce053274b7497ca0cbd41ade90374ae3fb5e6 100644 (file)
@@ -375,7 +375,7 @@ func continues() {
 
 func returns0() {
        return
-       return 0 /* ERROR no result values expected */
+       return 0 /* ERROR too many return values */
 }
 
 func returns1(x float64) (int, *float64) {
index 827b9b9d69c89de58578cff973000fef76fa7564..c3fe61c3d4901d4d651bf11f278e4b87967f5686 100644 (file)
@@ -177,8 +177,8 @@ func _() {
 
 func _() {
        var x int
-       return x /* ERROR no result values expected */
-       return math /* ERROR no result values expected */ .Sin(0)
+       return x /* ERROR too many return values */
+       return math /* ERROR too many return values */ .Sin(0)
 }
 
 func _() int {
index 0a69789078801d11beb598276e621d530cd2ec70..802673567d2b2b382fb54c4269cfd110e80838cc 100644 (file)
@@ -503,27 +503,25 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
 
        case *ast.ReturnStmt:
                res := check.sig.results
-               if res.Len() > 0 {
-                       // function returns results
-                       // (if one, say the first, result parameter is named, all of them are named)
-                       if len(s.Results) == 0 && res.vars[0].name != "" {
-                               // spec: "Implementation restriction: A compiler may disallow an empty expression
-                               // list in a "return" statement if a different entity (constant, type, or variable)
-                               // with the same name as a result parameter is in scope at the place of the return."
-                               for _, obj := range res.vars {
-                                       if alt := check.lookup(obj.name); alt != nil && alt != obj {
-                                               check.errorf(s, _OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
-                                               check.errorf(alt, _OutOfScopeResult, "\tinner declaration of %s", obj)
-                                               // ok to continue
-                                       }
+               // Return with implicit results allowed for function with named results.
+               // (If one is named, all are named.)
+               if len(s.Results) == 0 && res.Len() > 0 && res.vars[0].name != "" {
+                       // spec: "Implementation restriction: A compiler may disallow an empty expression
+                       // list in a "return" statement if a different entity (constant, type, or variable)
+                       // with the same name as a result parameter is in scope at the place of the return."
+                       for _, obj := range res.vars {
+                               if alt := check.lookup(obj.name); alt != nil && alt != obj {
+                                       check.errorf(s, _OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
+                                       check.errorf(alt, _OutOfScopeResult, "\tinner declaration of %s", obj)
+                                       // ok to continue
                                }
-                       } else {
-                               // return has results or result parameters are unnamed
-                               check.initVars(res.vars, s.Results, s)
                        }
-               } else if len(s.Results) > 0 {
-                       check.error(s.Results[0], _WrongResultCount, "no result values expected")
-                       check.use(s.Results...)
+               } else {
+                       var lhs []*Var
+                       if res.Len() > 0 {
+                               lhs = res.vars
+                       }
+                       check.initVars(lhs, s.Results, s)
                }
 
        case *ast.BranchStmt:
index a635af7cbbc11c7e703ce89435aa57ae196ff6d8..ec8bf71013e7770bad0645ed1270f68f7490364a 100644 (file)
@@ -375,7 +375,7 @@ func continues() {
 
 func returns0() {
        return
-       return 0 /* ERROR no result values expected */
+       return 0 /* ERROR too many return values */
 }
 
 func returns1(x float64) (int, *float64) {
index 787f7878f140b275b1e57763cd68cc18791776ef..56abf977224d5560539f4c1d0c3aaa1bdd5d736d 100644 (file)
@@ -169,8 +169,8 @@ func _() {
 
 func _() {
        var x int
-       return x /* ERROR no result values expected */
-       return math /* ERROR no result values expected */ .Sin(0)
+       return x /* ERROR too many return values */
+       return math /* ERROR too many return values */ .Sin(0)
 }
 
 func _() int {
index b6ece4bf21db0e02255f3603a3eeb5d49c1b1815..9f32f5b100649f87c3624045b0addbe3cd5580e8 100644 (file)
@@ -11,7 +11,7 @@ func foo() (int, int) {
 }
 
 func foo2() {
-       return int(2), 2 // ERROR "too many arguments to return\n\thave \(int, number\)\n\twant \(\)|return with value in function with no return type|no result values expected"
+       return int(2), 2 // ERROR "too many (arguments to return|return values)\n\thave \(int, number\)\n\twant \(\)|return with value in function with no return type"
 }
 
 func foo3(v int) (a, b, c, d int) {
index cf97d132c3f272d5a03b34946e4993df00499725..584dfa5764532ff8d5aac49ba2c0e7b7628004e7 100644 (file)
@@ -20,5 +20,5 @@ func _() int {
 }
 
 func _() {
-       return 1 // ERROR "too many arguments to return\n\thave \(number\)\n\twant \(\)|no result values expected"
+       return 1 // ERROR "too many (arguments to return|return values)\n\thave \(number\)\n\twant \(\)"
 }