import (
"cmd/compile/internal/types"
+ "fmt"
"sort"
)
typecheckslice(ncase.Nbody.Slice(), Etop)
}
+ switch top {
+ // expression switch
+ case Erv:
+ checkDupExprCases(n.Left, n.List.Slice())
+ }
}
// walkswitch walks a switch statement.
if cc.defjmp == nil {
cc.defjmp = nod(OBREAK, nil, nil)
}
-
- // diagnose duplicate cases
- s.checkDupCases(cc.list)
return cc
}
}
}
-func (s *exprSwitch) checkDupCases(cc []caseClause) {
- if len(cc) < 2 {
+func checkDupExprCases(exprname *Node, clauses []*Node) {
+ // boolean (naked) switch, nothing to do.
+ if exprname == nil {
return
}
// The common case is that s's expression is not an interface.
// In that case, all constant clauses have the same type,
// so checking for duplicates can be done solely by value.
- if !s.exprname.Type.IsInterface() {
+ if !exprname.Type.IsInterface() {
seen := make(map[interface{}]*Node)
- for _, c := range cc {
- switch {
- case c.node.Left != nil:
- // Single constant.
-
+ for _, ncase := range clauses {
+ for _, n := range ncase.List.Slice() {
// Can't check for duplicates that aren't constants, per the spec. Issue 15896.
// Don't check for duplicate bools. Although the spec allows it,
// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
// case GOARCH == "arm" && GOARM == "5":
// case GOARCH == "arm":
// which would both evaluate to false for non-ARM compiles.
- if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
+ if ct := consttype(n); ct < 0 || ct == CTBOOL {
continue
}
- val := c.node.Left.Val().Interface()
+ val := n.Val().Interface()
prev, dup := seen[val]
if !dup {
- seen[val] = c.node
+ seen[val] = n
continue
}
- setlineno(c.node)
- yyerror("duplicate case %#v in switch\n\tprevious case at %v", val, prev.Line())
-
- case c.node.List.Len() == 2:
- // Range of integers.
- low := c.node.List.First().Int64()
- high := c.node.List.Second().Int64()
- for i := low; i <= high; i++ {
- prev, dup := seen[i]
- if !dup {
- seen[i] = c.node
- continue
- }
- setlineno(c.node)
- yyerror("duplicate case %d in switch\n\tprevious case at %v", i, prev.Line())
- }
-
- default:
- Fatalf("bad caseClause node in checkDupCases: %v", c.node)
+ yyerrorl(ncase.Pos, "duplicate case %s in switch\n\tprevious case at %v",
+ nodeAndVal(n), prev.Line())
}
}
return
val interface{}
}
seen := make(map[typeVal]*Node)
- for _, c := range cc {
- if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
- continue
- }
- n := c.node.Left
- tv := typeVal{
- typ: n.Type.LongString(),
- val: n.Val().Interface(),
- }
- prev, dup := seen[tv]
- if !dup {
- seen[tv] = c.node
- continue
+ for _, ncase := range clauses {
+ for _, n := range ncase.List.Slice() {
+ if ct := consttype(n); ct < 0 || ct == CTBOOL {
+ continue
+ }
+ tv := typeVal{
+ typ: n.Type.LongString(),
+ val: n.Val().Interface(),
+ }
+ prev, dup := seen[tv]
+ if !dup {
+ seen[tv] = n
+ continue
+ }
+ yyerrorl(ncase.Pos, "duplicate case %s in switch\n\tprevious case at %v",
+ nodeAndVal(n), prev.Line())
}
- setlineno(c.node)
- yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line())
}
}
+func nodeAndVal(n *Node) string {
+ show := n.String()
+ val := n.Val().Interface()
+ if s := fmt.Sprintf("%#v", val); show != s {
+ show += " (value " + s + ")"
+ }
+ return show
+}
+
// walk generates an AST that implements sw,
// where sw is a type switch.
// The AST is generally of the form of a linear
package main
-import "fmt"
-
func f0(x int) {
switch x {
case 0:
switch x {
case 0:
- case int(0): // ERROR "duplicate case 0 in switch"
+ case int(0): // ERROR "duplicate case int.0. .value 0. in switch"
}
}
case 0: // ERROR "duplicate case 0 in switch"
case int64(0):
case float32(10):
- case float32(10): // ERROR "duplicate case float32\(10\) in switch"
+ case float32(10): // ERROR "duplicate case float32\(10\) .value 10. in switch"
case float64(10):
- case float64(10): // ERROR "duplicate case float64\(10\) in switch"
- }
-}
-
-func f4(e interface{}) {
- switch e.(type) {
- case int:
- case int: // ERROR "duplicate case int in type switch"
- case int64:
- case error:
- case error: // ERROR "duplicate case error in type switch"
- case fmt.Stringer:
- case fmt.Stringer: // ERROR "duplicate case fmt.Stringer in type switch"
- case struct {
- i int "tag1"
- }:
- case struct {
- i int "tag2"
- }:
- case struct { // ERROR "duplicate case struct { i int .tag1. } in type switch"
- i int "tag1"
- }:
+ case float64(10): // ERROR "duplicate case float64\(10\) .value 10. in switch"
}
}
case 1, 2, 3, 4: // ERROR "duplicate case 1"
}
}
+
+// Ensure duplicates with simple literals are printed as they were
+// written, not just their values. Particularly useful for runes.
+func f8(r rune) {
+ const x = 10
+ switch r {
+ case 33, 33: // ERROR "duplicate case 33 in switch"
+ case 34, '"': // ERROR "duplicate case '"' .value 34. in switch"
+ case 35, rune('#'): // ERROR "duplicate case rune.'#'. .value 35. in switch"
+ case 36, rune(36): // ERROR "duplicate case rune.36. .value 36. in switch"
+ case 37, '$'+1: // ERROR "duplicate case '\$' \+ 1 .value 37. in switch"
+ case 'b':
+ case 'a', 'b', 'c', 'd': // ERROR "duplicate case 'b' .value 98."
+ case x, x: // ERROR "duplicate case x .value 10."
+ }
+}