switchKindType // switch a.(type) {...}
)
-const (
- // expression switch
- caseKindExprConst = iota // case 5:
- caseKindExprVar // case x:
-
- // type switch
- caseKindTypeConst // case time.Time: (concrete type, has type hash)
- caseKindTypeVar // case io.Reader: (interface type)
-)
-
const binarySearchMin = 4 // minimum number of cases for binary search
// An exprSwitch walks an expression switch.
node *Node // points at case statement
ordinal int // position in switch
hash uint32 // hash of a type switch
- typ uint8 // type of case
+ // isconst indicates whether this case clause is a constant,
+ // for the purposes of the switch code generation.
+ // For expression switches, that's generally literals (case 5:, not case x:).
+ // For type switches, that's concrete types (case time.Time:), not interfaces (case io.Reader:).
+ isconst bool
}
// caseClauses are all the case clauses in a switch statement.
// handle the cases in order
for len(cc) > 0 {
// deal with expressions one at a time
- if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
+ if !okforcmp[t.Etype] || !cc[0].isconst {
a := s.walkCases(cc[:1])
cas = append(cas, a)
cc = cc[1:]
// do binary search on runs of constants
var run int
- for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
+ for run = 1; run < len(cc) && cc[run].isconst; run++ {
}
// sort and compile constants
c := caseClause{node: n, ordinal: len(cc.list)}
if kind == switchKindType {
// type switch
- switch {
- case n.Left.Type.IsInterface():
- c.typ = caseKindTypeVar
- default:
- c.typ = caseKindTypeConst
- }
+ c.isconst = !n.Left.Type.IsInterface()
c.hash = typehash(n.Left.Type)
} else {
// expression switch
switch consttype(n.Left) {
case CTFLT, CTINT, CTRUNE, CTSTR:
- c.typ = caseKindExprConst
- default:
- c.typ = caseKindExprVar
+ c.isconst = true
}
}
cc.list = append(cc.list, c)
// insert type equality check into each case block
for _, c := range cc {
- n := c.node
- switch c.typ {
- case caseKindTypeVar, caseKindTypeConst:
- n.Right = s.typeone(n)
- default:
- Fatalf("typeSwitch with bad kind: %d", c.typ)
- }
+ c.node.Right = s.typeone(c.node)
}
// generate list of if statements, binary search for constant sequences
for len(cc) > 0 {
- if cc[0].typ != caseKindTypeConst {
+ if !cc[0].isconst {
n := cc[0].node
cas = append(cas, n.Right)
cc = cc[1:]
// identify run of constants
var run int
- for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
+ for run = 1; run < len(cc) && cc[run].isconst; run++ {
}
// sort by hash
var cas []*Node
for _, c := range cc {
n := c.node
- if c.typ != caseKindTypeConst {
+ if !c.isconst {
Fatalf("typeSwitch walkCases")
}
a := Nod(OIF, nil, nil)
func exprcmp(c1, c2 caseClause) int {
// sort non-constants last
- if c1.typ != caseKindExprConst {
+ if !c1.isconst {
return +1
}
- if c2.typ != caseKindExprConst {
+ if !c2.isconst {
return -1
}
}{
// Non-constants.
{
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar},
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nil, nil)},
+ caseClause{node: Nod(OXXX, nil, nil), isconst: true},
+1,
},
{
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar},
+ caseClause{node: Nod(OXXX, nil, nil), isconst: true},
+ caseClause{node: Nod(OXXX, nil, nil)},
-1,
},
// Type switches
{
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
+ caseClause{node: Nod(OXXX, Nodbool(true), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, Nodbool(true), nil), isconst: true},
+ caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
+1,
},
{
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 0}}, nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), isconst: true},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 0}}, nil), isconst: true},
+1,
},
{
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), isconst: true},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 0}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 0}}, nil), isconst: true},
+ caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), isconst: true},
-1,
},
// Constant values.
// CTFLT
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
0,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), isconst: true},
+1,
},
// CTINT
{
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
+ caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
+ caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
0,
},
{
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, Nodintconst(1), nil), isconst: true},
+ caseClause{node: Nod(OXXX, Nodintconst(0), nil), isconst: true},
+1,
},
// CTRUNE
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
0,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), isconst: true},
+1,
},
// CTSTR
{
- caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), isconst: true},
-1,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
0,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), isconst: true},
+1,
},
{
- caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), isconst: true},
+1,
},
// Everything else should compare equal.
{
- caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst},
+ caseClause{node: Nod(OXXX, nodnil(), nil), isconst: true},
+ caseClause{node: Nod(OXXX, nodnil(), nil), isconst: true},
0,
},
}
got := exprcmp(d.a, d.b)
if d.want != got {
t.Errorf("%d: exprcmp(a, b) = %d; want %d", i, got, d.want)
- t.Logf("\ta = caseClause{node: %#v, typ: %#v}", d.a.node, d.a.typ)
- t.Logf("\tb = caseClause{node: %#v, typ: %#v}", d.b.node, d.b.typ)
+ t.Logf("\ta = caseClause{node: %#v, isconst: %v}", d.a.node, d.a.isconst)
+ t.Logf("\tb = caseClause{node: %#v, isconst: %v}", d.b.node, d.b.isconst)
}
}
}