Skip to content

Commit

Permalink
cmd/compile, go/types: fix checking of bad type switch
Browse files Browse the repository at this point in the history
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 golang#50493.

Change-Id: I317883f29077b1b4bbd0e8793617fd3bb31aa0f8
Reviewed-on: https://go-review.googlesource.com/c/go/+/379117
Trust: Russ Cox <[email protected]>
Run-TryBot: Russ Cox <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
rsc committed Jan 18, 2022
1 parent 75bcdd5 commit 46f138f
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 16 deletions.
15 changes: 8 additions & 7 deletions src/cmd/compile/internal/types2/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ L:
}
}
seen[T] = e
if T != nil {
if T != nil && xtyp != nil {
check.typeAssertion(e, x, xtyp, T, true)
}
}
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion src/cmd/compile/internal/types2/testdata/check/stmt0.src
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down
14 changes: 7 additions & 7 deletions src/go/types/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ L:
}
}
seen[T] = e
if T != nil {
if T != nil && xtyp != nil {
check.typeAssertion(e, x, xtyp, T)
}
}
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion src/go/types/testdata/check/stmt0.src
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down

0 comments on commit 46f138f

Please sign in to comment.