]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, go/types: fix checking of bad type switch
authorRuss Cox <rsc@golang.org>
Tue, 18 Jan 2022 15:49:57 +0000 (10:49 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 18 Jan 2022 19:03:00 +0000 (19:03 +0000)
Consider the following program:

package p

func f() {
x := 1
v := 2
switch v.(type) {
case int:
println(x)
println(x / 0)
case 1:
}
}

Before this CL, the compiler prints:

x.go:4:2: x declared but not used
x.go:6:9: v (variable of type int) is not an interface

x is in fact used, and other errors in the switch go undiagnosed.

This commit fixes that problem by processing the switch statement
even when the 'not an interface' error is reported.

Now the compiler drops the spurious 'declared but not used'
and adds two previously undiagnosed problems:

x.go:6:9: v (variable of type int) is not an interface
x.go:9:15: invalid operation: division by zero
x.go:10:7: 1 is not a type

go/types was printing roughly the same thing the compiler did before,
and now still prints roughly the same thing the compiler does after.
(The only differences are in the exact reported columns.)

Fixes #50493.

Change-Id: I317883f29077b1b4bbd0e8793617fd3bb31aa0f8
Reviewed-on: https://go-review.googlesource.com/c/go/+/379117
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/go/types/stmt.go
src/go/types/testdata/check/stmt0.src

index ae9cc69c99691530c3302b2f48d769416079b2e4..98244cd5e979c6d2ac5f46606f56b424561b1474 100644 (file)
@@ -305,7 +305,7 @@ L:
                        }
                }
                seen[T] = e
-               if T != nil {
+               if T != nil && xtyp != nil {
                        check.typeAssertion(e, x, xtyp, T, true)
                }
        }
@@ -733,15 +733,16 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
        if x.mode == invalid {
                return
        }
+
        // TODO(gri) we may want to permit type switches on type parameter values at some point
+       var xtyp *Interface
        if isTypeParam(x.typ) {
                check.errorf(&x, "cannot use type switch on type parameter value %s", &x)
-               return
-       }
-       xtyp, _ := under(x.typ).(*Interface)
-       if xtyp == nil {
-               check.errorf(&x, "%s is not an interface", &x)
-               return
+       } else {
+               xtyp, _ = under(x.typ).(*Interface)
+               if xtyp == nil {
+                       check.errorf(&x, "%s is not an interface", &x)
+               }
        }
 
        check.multipleSwitchDefaults(s.Body)
index 8b18d676ac258513eb68f2a7a254219c3b7ff606..c4820c9f7fa0bc694f7f9dabcfa239163b542364 100644 (file)
@@ -695,7 +695,7 @@ func typeswitches() {
                _ = y
        }
 
-       switch x := i /* ERROR "not an interface" */ .(type) {}
+       switch /* ERROR "x declared but not used" */ x := i /* ERROR "not an interface" */ .(type) {}
 
        switch t := x.(type) {
        case nil:
@@ -719,6 +719,18 @@ func typeswitches() {
        case T2 /* ERROR "wrong type for method m" */ :
        case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
        }
+
+
+       {
+               x := 1
+               v := 2
+               switch v /* ERROR "v [(]variable of type int[)] is not an interface" */ .(type) {
+               case int:
+                       println(x)
+                       println(x / /* ERROR "invalid operation: division by zero" */ 0)
+               case /* ERROR "1 is not a type" */ 1:
+               }
+       }
 }
 
 // Test that each case clause uses the correct type of the variable
index 8621d2800a54ac8edb3c0306b4889b1d7eb64a45..0a69789078801d11beb598276e621d530cd2ec70 100644 (file)
@@ -310,7 +310,7 @@ L:
                        }
                }
                seen[T] = e
-               if T != nil {
+               if T != nil && xtyp != nil {
                        check.typeAssertion(e, x, xtyp, T)
                }
        }
@@ -686,14 +686,14 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
                        return
                }
                // TODO(gri) we may want to permit type switches on type parameter values at some point
+               var xtyp *Interface
                if isTypeParam(x.typ) {
                        check.errorf(&x, _InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
-                       return
-               }
-               xtyp, _ := under(x.typ).(*Interface)
-               if xtyp == nil {
-                       check.errorf(&x, _InvalidTypeSwitch, "%s is not an interface", &x)
-                       return
+               } else {
+                       xtyp, _ = under(x.typ).(*Interface)
+                       if xtyp == nil {
+                               check.errorf(&x, _InvalidTypeSwitch, "%s is not an interface", &x)
+                       }
                }
 
                check.multipleDefaults(s.Body.List)
index c7a718de70e50286ef53d68f0888b5b8a1b68ce8..a635af7cbbc11c7e703ce89435aa57ae196ff6d8 100644 (file)
@@ -695,7 +695,7 @@ func typeswitches() {
                _ = y
        }
 
-       switch x := i /* ERROR "not an interface" */ .(type) {}
+       switch x /* ERROR "x declared but not used" */ := i /* ERROR "not an interface" */ .(type) {}
 
        switch t := x.(type) {
        case nil:
@@ -719,6 +719,18 @@ func typeswitches() {
        case T2 /* ERROR "wrong type for method m" */ :
        case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
        }
+
+
+       {
+               x := 1
+               v := 2
+               switch v /* ERROR "v [(]variable of type int[)] is not an interface" */ .(type) {
+               case int:
+                       println(x)
+                       println(x / 0 /* ERROR "invalid operation: division by zero" */)
+               case 1 /* ERROR "expected type, found 1" */:
+               }
+       }
 }
 
 // Test that each case clause uses the correct type of the variable