]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: better error msg when using fallthrough in type switch
authorRobert Griesemer <gri@golang.org>
Mon, 14 Mar 2022 21:05:53 +0000 (14:05 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 21 Mar 2022 19:10:22 +0000 (19:10 +0000)
Fixes #51533.

Change-Id: Ia41a2e96d1ef94f740887e3167e6396e4f52035c
Reviewed-on: https://go-review.googlesource.com/c/go/+/392759
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/testdata/check/stmt0.src
src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go [new file with mode: 0644]
src/go/types/stmt.go
src/go/types/testdata/check/stmt0.src
src/go/types/testdata/fixedbugs/issue51533.go [new file with mode: 0644]

index 4c8eac725f6f0761ac6695c420e627e384b38ad2..819b7c2463d6bbb39c4db30dc37d492d323dd7d0 100644 (file)
@@ -95,6 +95,7 @@ const (
 
        // additional context information
        finalSwitchCase
+       inTypeSwitch
 )
 
 func (check *Checker) simpleStmt(s syntax.Stmt) {
@@ -370,7 +371,9 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
        // process collected function literals before scope changes
        defer check.processDelayed(len(check.delayed))
 
-       inner := ctxt &^ (fallthroughOk | finalSwitchCase)
+       // reset context for statements of inner blocks
+       inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch)
+
        switch s := s.(type) {
        case *syntax.EmptyStmt:
                // ignore
@@ -523,9 +526,14 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                        }
                case syntax.Fallthrough:
                        if ctxt&fallthroughOk == 0 {
-                               msg := "fallthrough statement out of place"
-                               if ctxt&finalSwitchCase != 0 {
+                               var msg string
+                               switch {
+                               case ctxt&finalSwitchCase != 0:
                                        msg = "cannot fallthrough final case in switch"
+                               case ctxt&inTypeSwitch != 0:
+                                       msg = "cannot fallthrough in type switch"
+                               default:
+                                       msg = "fallthrough statement out of place"
                                }
                                check.error(s, msg)
                        }
@@ -572,7 +580,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) {
                check.simpleStmt(s.Init)
 
                if g, _ := s.Tag.(*syntax.TypeSwitchGuard); g != nil {
-                       check.typeSwitchStmt(inner, s, g)
+                       check.typeSwitchStmt(inner|inTypeSwitch, s, g)
                } else {
                        check.switchStmt(inner, s)
                }
index 90ef09511f7bcb098781cf6f469e413334bee323..e5b6f5dff740be386cc69ec26b4bd32a1b67a0b4 100644 (file)
@@ -542,7 +542,7 @@ func switches1() {
        var y interface{}
        switch y.(type) {
        case int:
-               fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ;
+               fallthrough /* ERROR "cannot fallthrough in type switch" */ ; ; ;
        default:
        }
 
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go
new file mode 100644 (file)
index 0000000..bf46f75
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2022 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 _(x any) {
+       switch x {
+       case 0:
+               fallthrough // ERROR fallthrough statement out of place
+               _ = x
+       default:
+       }
+
+       switch x.(type) {
+       case int:
+               fallthrough // ERROR cannot fallthrough in type switch
+       default:
+       }
+}
index 9ebfbb6d6370296a361a03e11311d46decdb2d66..2aa65a6e36eea15ea22a5f001ee9449c631ea1f8 100644 (file)
@@ -96,6 +96,7 @@ const (
 
        // additional context information
        finalSwitchCase
+       inTypeSwitch
 )
 
 func (check *Checker) simpleStmt(s ast.Stmt) {
@@ -375,7 +376,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
        // process collected function literals before scope changes
        defer check.processDelayed(len(check.delayed))
 
-       inner := ctxt &^ (fallthroughOk | finalSwitchCase)
+       // reset context for statements of inner blocks
+       inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch)
+
        switch s := s.(type) {
        case *ast.BadStmt, *ast.EmptyStmt:
                // ignore
@@ -541,12 +544,16 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                        }
                case token.FALLTHROUGH:
                        if ctxt&fallthroughOk == 0 {
-                               msg := "fallthrough statement out of place"
-                               code := _MisplacedFallthrough
-                               if ctxt&finalSwitchCase != 0 {
+                               var msg string
+                               switch {
+                               case ctxt&finalSwitchCase != 0:
                                        msg = "cannot fallthrough final case in switch"
+                               case ctxt&inTypeSwitch != 0:
+                                       msg = "cannot fallthrough in type switch"
+                               default:
+                                       msg = "fallthrough statement out of place"
                                }
-                               check.error(s, code, msg)
+                               check.error(s, _MisplacedFallthrough, msg)
                        }
                default:
                        check.invalidAST(s, "branch statement: %s", s.Tok)
@@ -627,7 +634,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                }
 
        case *ast.TypeSwitchStmt:
-               inner |= breakOk
+               inner |= breakOk | inTypeSwitch
                check.openScope(s, "type switch")
                defer check.closeScope()
 
index 7795a442aae73d8bc1b80bb2846f9b4de97f22d4..0f164d36c8bfa46e29c2df28d2425fe340154dcf 100644 (file)
@@ -542,7 +542,7 @@ func switches1() {
        var y interface{}
        switch y.(type) {
        case int:
-               fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ;
+               fallthrough /* ERROR "cannot fallthrough in type switch" */ ; ; ;
        default:
        }
 
diff --git a/src/go/types/testdata/fixedbugs/issue51533.go b/src/go/types/testdata/fixedbugs/issue51533.go
new file mode 100644 (file)
index 0000000..bf46f75
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2022 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 _(x any) {
+       switch x {
+       case 0:
+               fallthrough // ERROR fallthrough statement out of place
+               _ = x
+       default:
+       }
+
+       switch x.(type) {
+       case int:
+               fallthrough // ERROR cannot fallthrough in type switch
+       default:
+       }
+}