@@ -323,15 +323,7 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
323
323
half := len (cc ) / 2
324
324
a := Nod (OIF , nil , nil )
325
325
mid := cc [half - 1 ].node .Left
326
- le := Nod (OLE , s .exprname , mid )
327
- if Isconst (mid , CTSTR ) {
328
- // Search by length and then by value; see exprcmp.
329
- lenlt := Nod (OLT , Nod (OLEN , s .exprname , nil ), Nod (OLEN , mid , nil ))
330
- leneq := Nod (OEQ , Nod (OLEN , s .exprname , nil ), Nod (OLEN , mid , nil ))
331
- a .Left = Nod (OOROR , lenlt , Nod (OANDAND , leneq , le ))
332
- } else {
333
- a .Left = le
334
- }
326
+ a .Left = caseLessEq (s .exprname , mid )
335
327
a .Left = typecheck (a .Left , Erv )
336
328
a .Nbody .Set1 (s .walkCases (cc [:half ]))
337
329
a .Rlist .Set1 (s .walkCases (cc [half :]))
@@ -463,10 +455,9 @@ func caseClauses(sw *Node, kind int) []*caseClause {
463
455
}
464
456
} else {
465
457
// expression switch
466
- switch consttype (n .Left ) {
467
- case CTFLT , CTINT , CTRUNE , CTSTR :
458
+ if caseIsConst (n .Left ) {
468
459
c .typ = caseKindExprConst
469
- default :
460
+ } else {
470
461
c .typ = caseKindExprVar
471
462
}
472
463
}
@@ -799,7 +790,67 @@ func exprcmp(c1, c2 *caseClause) int {
799
790
}
800
791
}
801
792
793
+ if ! caseIsConst (n1 ) {
794
+ return 0
795
+ }
796
+
802
797
// sort by constant value to enable binary search
798
+ return caseConstCompare (n1 , n2 )
799
+ }
800
+
801
+ type caseClauseByType []* caseClause
802
+
803
+ func (x caseClauseByType ) Len () int { return len (x ) }
804
+ func (x caseClauseByType ) Swap (i , j int ) { x [i ], x [j ] = x [j ], x [i ] }
805
+ func (x caseClauseByType ) Less (i , j int ) bool {
806
+ c1 , c2 := x [i ], x [j ]
807
+ switch {
808
+ // sort non-constants last
809
+ case c1 .typ != caseKindTypeConst :
810
+ return false
811
+ case c2 .typ != caseKindTypeConst :
812
+ return true
813
+
814
+ // sort by hash code
815
+ case c1 .hash != c2 .hash :
816
+ return c1 .hash < c2 .hash
817
+ }
818
+
819
+ // sort by ordinal
820
+ return c1 .ordinal < c2 .ordinal
821
+ }
822
+
823
+ // caseIsConst reports whether n can be treated as a constant case in an expression switch.
824
+ // This includes regular Go constants, but it could also include expressions
825
+ // whose value is fixed at compile time, such as [3]array{1, 2, 3}.
826
+ func caseIsConst (n * Node ) bool {
827
+ switch consttype (n ) {
828
+ case CTFLT , CTINT , CTRUNE , CTSTR :
829
+ return true
830
+ }
831
+ return false
832
+ }
833
+
834
+ // caseLessEq generates a Node representing "expr <= mid" for a binary search over constant cases.
835
+ // mid is guaranteed to be a constant case, as defined by caseIsConst.
836
+ // caseConstCompare and caseLessEq must agree on the sort order.
837
+ func caseLessEq (expr , mid * Node ) * Node {
838
+ le := Nod (OLE , expr , mid )
839
+ if Isconst (mid , CTSTR ) {
840
+ // Search by length and then by value; see caseConstCompare.
841
+ lenlt := Nod (OLT , Nod (OLEN , expr , nil ), Nod (OLEN , mid , nil ))
842
+ leneq := Nod (OEQ , Nod (OLEN , expr , nil ), Nod (OLEN , mid , nil ))
843
+ le = Nod (OOROR , lenlt , Nod (OANDAND , leneq , le ))
844
+ }
845
+ return le
846
+ }
847
+
848
+ // caseConstCompare provides a sort indicator (+1, 0, -1) for expressions n1 and n2.
849
+ // n1 and n2 will be constants, as defined by caseIsConst.
850
+ // This sort indicator will be used to sort the cases for binary searching.
851
+ // caseConstCompare and caseLessEq must agree on the sort order.
852
+ func caseConstCompare (n1 , n2 * Node ) int {
853
+ ct := n1 .Val ().Ctype ()
803
854
switch ct {
804
855
case CTFLT :
805
856
return n1 .Val ().U .(* Mpflt ).Cmp (n2 .Val ().U .(* Mpflt ))
@@ -809,7 +860,7 @@ func exprcmp(c1, c2 *caseClause) int {
809
860
// Sort strings by length and then by value.
810
861
// It is much cheaper to compare lengths than values,
811
862
// and all we need here is consistency.
812
- // We respect this sorting in exprSwitch.walkCases .
863
+ // We respect this sorting in caseLessEq .
813
864
a := n1 .Val ().U .(string )
814
865
b := n2 .Val ().U .(string )
815
866
if len (a ) < len (b ) {
@@ -826,28 +877,6 @@ func exprcmp(c1, c2 *caseClause) int {
826
877
}
827
878
return + 1
828
879
}
829
-
880
+ Fatalf ( "caseConstCompare non-const nodes %v / %v" , n1 , n2 )
830
881
return 0
831
882
}
832
-
833
- type caseClauseByType []* caseClause
834
-
835
- func (x caseClauseByType ) Len () int { return len (x ) }
836
- func (x caseClauseByType ) Swap (i , j int ) { x [i ], x [j ] = x [j ], x [i ] }
837
- func (x caseClauseByType ) Less (i , j int ) bool {
838
- c1 , c2 := x [i ], x [j ]
839
- switch {
840
- // sort non-constants last
841
- case c1 .typ != caseKindTypeConst :
842
- return false
843
- case c2 .typ != caseKindTypeConst :
844
- return true
845
-
846
- // sort by hash code
847
- case c1 .hash != c2 .hash :
848
- return c1 .hash < c2 .hash
849
- }
850
-
851
- // sort by ordinal
852
- return c1 .ordinal < c2 .ordinal
853
- }
0 commit comments