github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/src/cmd/compile/internal/gc/swt.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "sort" 10 "strconv" 11 ) 12 13 const ( 14 // expression switch 15 switchKindExpr = iota // switch a {...} or switch 5 {...} 16 switchKindTrue // switch true {...} or switch {...} 17 switchKindFalse // switch false {...} 18 19 // type switch 20 switchKindType // switch a.(type) {...} 21 ) 22 23 const ( 24 caseKindDefault = iota // default: 25 26 // expression switch 27 caseKindExprConst // case 5: 28 caseKindExprVar // case x: 29 30 // type switch 31 caseKindTypeNil // case nil: 32 caseKindTypeConst // case time.Time: (concrete type, has type hash) 33 caseKindTypeVar // case io.Reader: (interface type) 34 ) 35 36 const binarySearchMin = 4 // minimum number of cases for binary search 37 38 // An exprSwitch walks an expression switch. 39 type exprSwitch struct { 40 exprname *Node // node for the expression being switched on 41 kind int // kind of switch statement (switchKind*) 42 } 43 44 // A typeSwitch walks a type switch. 45 type typeSwitch struct { 46 hashname *Node // node for the hash of the type of the variable being switched on 47 facename *Node // node for the concrete type of the variable being switched on 48 okname *Node // boolean node used for comma-ok type assertions 49 } 50 51 // A caseClause is a single case clause in a switch statement. 52 type caseClause struct { 53 node *Node // points at case statement 54 ordinal int // position in switch 55 hash uint32 // hash of a type switch 56 typ uint8 // type of case 57 } 58 59 // typecheckswitch typechecks a switch statement. 60 func typecheckswitch(n *Node) { 61 lno := int(lineno) 62 typechecklist(n.Ninit, Etop) 63 64 var nilonly string 65 var top int 66 var t *Type 67 68 if n.Left != nil && n.Left.Op == OTYPESW { 69 // type switch 70 top = Etype 71 typecheck(&n.Left.Right, Erv) 72 t = n.Left.Right.Type 73 if t != nil && t.Etype != TINTER { 74 Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, obj.FmtLong)) 75 } 76 } else { 77 // expression switch 78 top = Erv 79 if n.Left != nil { 80 typecheck(&n.Left, Erv) 81 defaultlit(&n.Left, nil) 82 t = n.Left.Type 83 } else { 84 t = Types[TBOOL] 85 } 86 if t != nil { 87 var badtype *Type 88 switch { 89 case !okforeq[t.Etype]: 90 Yyerror("cannot switch on %v", Nconv(n.Left, obj.FmtLong)) 91 case t.Etype == TARRAY && !Isfixedarray(t): 92 nilonly = "slice" 93 case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ: 94 Yyerror("cannot switch on %v", Nconv(n.Left, obj.FmtLong)) 95 case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ: 96 Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, obj.FmtLong), badtype) 97 case t.Etype == TFUNC: 98 nilonly = "func" 99 case t.Etype == TMAP: 100 nilonly = "map" 101 } 102 } 103 } 104 105 n.Type = t 106 107 var def *Node 108 var ll *NodeList 109 for l := n.List; l != nil; l = l.Next { 110 ncase := l.N 111 setlineno(n) 112 if ncase.List == nil { 113 // default 114 if def != nil { 115 Yyerror("multiple defaults in switch (first at %v)", def.Line()) 116 } else { 117 def = ncase 118 } 119 } else { 120 for ll = ncase.List; ll != nil; ll = ll.Next { 121 setlineno(ll.N) 122 typecheck(&ll.N, Erv|Etype) 123 if ll.N.Type == nil || t == nil { 124 continue 125 } 126 setlineno(ncase) 127 switch top { 128 // expression switch 129 case Erv: 130 defaultlit(&ll.N, t) 131 switch { 132 case ll.N.Op == OTYPE: 133 Yyerror("type %v is not an expression", ll.N.Type) 134 case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0: 135 if n.Left != nil { 136 Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", ll.N, n.Left, ll.N.Type, t) 137 } else { 138 Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type) 139 } 140 case nilonly != "" && !isnil(ll.N): 141 Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Left) 142 case Isinter(t) && !Isinter(ll.N.Type) && algtype1(ll.N.Type, nil) == ANOEQ: 143 Yyerror("invalid case %v in switch (incomparable type)", Nconv(ll.N, obj.FmtLong)) 144 } 145 146 // type switch 147 case Etype: 148 var missing, have *Type 149 var ptr int 150 switch { 151 case ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL): 152 case ll.N.Op != OTYPE && ll.N.Type != nil: // should this be ||? 153 Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong)) 154 // reset to original type 155 ll.N = n.Left.Right 156 case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr): 157 if have != nil && !missing.Broke && !have.Broke { 158 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort), missing.Sym, Tconv(missing.Type, obj.FmtShort)) 159 } else if !missing.Broke { 160 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym) 161 } 162 } 163 } 164 } 165 } 166 167 if top == Etype && n.Type != nil { 168 ll = ncase.List 169 if ncase.Rlist != nil { 170 nvar := ncase.Rlist.N 171 if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) { 172 // single entry type switch 173 nvar.Name.Param.Ntype = typenod(ll.N.Type) 174 } else { 175 // multiple entry type switch or default 176 nvar.Name.Param.Ntype = typenod(n.Type) 177 } 178 179 typecheck(&nvar, Erv|Easgn) 180 ncase.Rlist.N = nvar 181 } 182 } 183 184 typechecklist(ncase.Nbody, Etop) 185 } 186 187 lineno = int32(lno) 188 } 189 190 // walkswitch walks a switch statement. 191 func walkswitch(sw *Node) { 192 // convert switch {...} to switch true {...} 193 if sw.Left == nil { 194 sw.Left = Nodbool(true) 195 typecheck(&sw.Left, Erv) 196 } 197 198 if sw.Left.Op == OTYPESW { 199 var s typeSwitch 200 s.walk(sw) 201 } else { 202 var s exprSwitch 203 s.walk(sw) 204 } 205 } 206 207 // walk generates an AST implementing sw. 208 // sw is an expression switch. 209 // The AST is generally of the form of a linear 210 // search using if..goto, although binary search 211 // is used with long runs of constants. 212 func (s *exprSwitch) walk(sw *Node) { 213 casebody(sw, nil) 214 215 cond := sw.Left 216 sw.Left = nil 217 218 s.kind = switchKindExpr 219 if Isconst(cond, CTBOOL) { 220 s.kind = switchKindTrue 221 if !cond.Val().U.(bool) { 222 s.kind = switchKindFalse 223 } 224 } 225 226 walkexpr(&cond, &sw.Ninit) 227 t := sw.Type 228 if t == nil { 229 return 230 } 231 232 // convert the switch into OIF statements 233 var cas *NodeList 234 if s.kind == switchKindTrue || s.kind == switchKindFalse { 235 s.exprname = Nodbool(s.kind == switchKindTrue) 236 } else if consttype(cond) >= 0 { 237 // leave constants to enable dead code elimination (issue 9608) 238 s.exprname = cond 239 } else { 240 s.exprname = temp(cond.Type) 241 cas = list1(Nod(OAS, s.exprname, cond)) 242 typechecklist(cas, Etop) 243 } 244 245 // enumerate the cases, and lop off the default case 246 cc := caseClauses(sw, s.kind) 247 sw.List = nil 248 var def *Node 249 if len(cc) > 0 && cc[0].typ == caseKindDefault { 250 def = cc[0].node.Right 251 cc = cc[1:] 252 } else { 253 def = Nod(OBREAK, nil, nil) 254 } 255 256 // handle the cases in order 257 for len(cc) > 0 { 258 // deal with expressions one at a time 259 if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst { 260 a := s.walkCases(cc[:1]) 261 cas = list(cas, a) 262 cc = cc[1:] 263 continue 264 } 265 266 // do binary search on runs of constants 267 var run int 268 for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ { 269 } 270 271 // sort and compile constants 272 sort.Sort(caseClauseByExpr(cc[:run])) 273 a := s.walkCases(cc[:run]) 274 cas = list(cas, a) 275 cc = cc[run:] 276 } 277 278 // handle default case 279 if nerrors == 0 { 280 cas = list(cas, def) 281 sw.Nbody = concat(cas, sw.Nbody) 282 walkstmtlist(sw.Nbody) 283 } 284 } 285 286 // walkCases generates an AST implementing the cases in cc. 287 func (s *exprSwitch) walkCases(cc []*caseClause) *Node { 288 if len(cc) < binarySearchMin { 289 // linear search 290 var cas *NodeList 291 for _, c := range cc { 292 n := c.node 293 lno := int(setlineno(n)) 294 295 a := Nod(OIF, nil, nil) 296 if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE { 297 a.Left = Nod(OEQ, s.exprname, n.Left) // if name == val 298 typecheck(&a.Left, Erv) 299 } else if s.kind == switchKindTrue { 300 a.Left = n.Left // if val 301 } else { 302 // s.kind == switchKindFalse 303 a.Left = Nod(ONOT, n.Left, nil) // if !val 304 typecheck(&a.Left, Erv) 305 } 306 a.Nbody = list1(n.Right) // goto l 307 308 cas = list(cas, a) 309 lineno = int32(lno) 310 } 311 return liststmt(cas) 312 } 313 314 // find the middle and recur 315 half := len(cc) / 2 316 a := Nod(OIF, nil, nil) 317 mid := cc[half-1].node.Left 318 le := Nod(OLE, s.exprname, mid) 319 if Isconst(mid, CTSTR) { 320 // Search by length and then by value; see exprcmp. 321 lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil)) 322 leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil)) 323 a.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le)) 324 } else { 325 a.Left = le 326 } 327 typecheck(&a.Left, Erv) 328 a.Nbody = list1(s.walkCases(cc[:half])) 329 a.Rlist = list1(s.walkCases(cc[half:])) 330 return a 331 } 332 333 // casebody builds separate lists of statements and cases. 334 // It makes labels between cases and statements 335 // and deals with fallthrough, break, and unreachable statements. 336 func casebody(sw *Node, typeswvar *Node) { 337 if sw.List == nil { 338 return 339 } 340 341 lno := setlineno(sw) 342 343 var cas *NodeList // cases 344 var stat *NodeList // statements 345 var def *Node // defaults 346 br := Nod(OBREAK, nil, nil) 347 348 for l := sw.List; l != nil; l = l.Next { 349 n := l.N 350 setlineno(n) 351 if n.Op != OXCASE { 352 Fatalf("casebody %v", Oconv(int(n.Op), 0)) 353 } 354 n.Op = OCASE 355 needvar := count(n.List) != 1 || n.List.N.Op == OLITERAL 356 357 jmp := Nod(OGOTO, newCaseLabel(), nil) 358 if n.List == nil { 359 if def != nil { 360 Yyerror("more than one default case") 361 } 362 // reuse original default case 363 n.Right = jmp 364 def = n 365 } 366 367 if n.List != nil && n.List.Next == nil { 368 // one case -- reuse OCASE node 369 n.Left = n.List.N 370 n.Right = jmp 371 n.List = nil 372 cas = list(cas, n) 373 } else { 374 // expand multi-valued cases 375 for lc := n.List; lc != nil; lc = lc.Next { 376 cas = list(cas, Nod(OCASE, lc.N, jmp)) 377 } 378 } 379 380 stat = list(stat, Nod(OLABEL, jmp.Left, nil)) 381 if typeswvar != nil && needvar && n.Rlist != nil { 382 l := list1(Nod(ODCL, n.Rlist.N, nil)) 383 l = list(l, Nod(OAS, n.Rlist.N, typeswvar)) 384 typechecklist(l, Etop) 385 stat = concat(stat, l) 386 } 387 stat = concat(stat, n.Nbody) 388 389 // botch - shouldn't fall thru declaration 390 last := stat.End.N 391 if last.Xoffset == n.Xoffset && last.Op == OXFALL { 392 if typeswvar != nil { 393 setlineno(last) 394 Yyerror("cannot fallthrough in type switch") 395 } 396 397 if l.Next == nil { 398 setlineno(last) 399 Yyerror("cannot fallthrough final case in switch") 400 } 401 402 last.Op = OFALL 403 } else { 404 stat = list(stat, br) 405 } 406 } 407 408 stat = list(stat, br) 409 if def != nil { 410 cas = list(cas, def) 411 } 412 413 sw.List = cas 414 sw.Nbody = stat 415 lineno = lno 416 } 417 418 // nSwitchLabel is the number of switch labels generated. 419 // This should be per-function, but it is a global counter for now. 420 var nSwitchLabel int 421 422 func newCaseLabel() *Node { 423 label := strconv.Itoa(nSwitchLabel) 424 nSwitchLabel++ 425 return newname(Lookup(label)) 426 } 427 428 // caseClauses generates a slice of caseClauses 429 // corresponding to the clauses in the switch statement sw. 430 // Kind is the kind of switch statement. 431 func caseClauses(sw *Node, kind int) []*caseClause { 432 var cc []*caseClause 433 for l := sw.List; l != nil; l = l.Next { 434 n := l.N 435 c := new(caseClause) 436 cc = append(cc, c) 437 c.ordinal = len(cc) 438 c.node = n 439 440 if n.Left == nil { 441 c.typ = caseKindDefault 442 continue 443 } 444 445 if kind == switchKindType { 446 // type switch 447 switch { 448 case n.Left.Op == OLITERAL: 449 c.typ = caseKindTypeNil 450 case Istype(n.Left.Type, TINTER): 451 c.typ = caseKindTypeVar 452 default: 453 c.typ = caseKindTypeConst 454 c.hash = typehash(n.Left.Type) 455 } 456 } else { 457 // expression switch 458 switch consttype(n.Left) { 459 case CTFLT, CTINT, CTRUNE, CTSTR: 460 c.typ = caseKindExprConst 461 default: 462 c.typ = caseKindExprVar 463 } 464 } 465 } 466 467 if cc == nil { 468 return nil 469 } 470 471 // sort by value and diagnose duplicate cases 472 if kind == switchKindType { 473 // type switch 474 sort.Sort(caseClauseByType(cc)) 475 for i, c1 := range cc { 476 if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault { 477 break 478 } 479 for _, c2 := range cc[i+1:] { 480 if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash { 481 break 482 } 483 if Eqtype(c1.node.Left.Type, c2.node.Left.Type) { 484 yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line()) 485 } 486 } 487 } 488 } else { 489 // expression switch 490 sort.Sort(caseClauseByExpr(cc)) 491 for i, c1 := range cc { 492 if i+1 == len(cc) { 493 break 494 } 495 c2 := cc[i+1] 496 if exprcmp(c1, c2) != 0 { 497 continue 498 } 499 setlineno(c2.node) 500 Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line()) 501 } 502 } 503 504 // put list back in processing order 505 sort.Sort(caseClauseByOrd(cc)) 506 return cc 507 } 508 509 // walk generates an AST that implements sw, 510 // where sw is a type switch. 511 // The AST is generally of the form of a linear 512 // search using if..goto, although binary search 513 // is used with long runs of concrete types. 514 func (s *typeSwitch) walk(sw *Node) { 515 cond := sw.Left 516 sw.Left = nil 517 518 if cond == nil { 519 sw.List = nil 520 return 521 } 522 if cond.Right == nil { 523 setlineno(sw) 524 Yyerror("type switch must have an assignment") 525 return 526 } 527 528 walkexpr(&cond.Right, &sw.Ninit) 529 if !Istype(cond.Right.Type, TINTER) { 530 Yyerror("type switch must be on an interface") 531 return 532 } 533 534 var cas *NodeList 535 536 // predeclare temporary variables and the boolean var 537 s.facename = temp(cond.Right.Type) 538 539 a := Nod(OAS, s.facename, cond.Right) 540 typecheck(&a, Etop) 541 cas = list(cas, a) 542 543 s.okname = temp(Types[TBOOL]) 544 typecheck(&s.okname, Erv) 545 546 s.hashname = temp(Types[TUINT32]) 547 typecheck(&s.hashname, Erv) 548 549 // set up labels and jumps 550 casebody(sw, s.facename) 551 552 // calculate type hash 553 t := cond.Right.Type 554 if isnilinter(t) { 555 a = syslook("efacethash", 1) 556 } else { 557 a = syslook("ifacethash", 1) 558 } 559 substArgTypes(a, t) 560 a = Nod(OCALL, a, nil) 561 a.List = list1(s.facename) 562 a = Nod(OAS, s.hashname, a) 563 typecheck(&a, Etop) 564 cas = list(cas, a) 565 566 cc := caseClauses(sw, switchKindType) 567 sw.List = nil 568 var def *Node 569 if len(cc) > 0 && cc[0].typ == caseKindDefault { 570 def = cc[0].node.Right 571 cc = cc[1:] 572 } else { 573 def = Nod(OBREAK, nil, nil) 574 } 575 576 // insert type equality check into each case block 577 for _, c := range cc { 578 n := c.node 579 switch c.typ { 580 case caseKindTypeNil: 581 var v Val 582 v.U = new(NilVal) 583 a = Nod(OIF, nil, nil) 584 a.Left = Nod(OEQ, s.facename, nodlit(v)) 585 typecheck(&a.Left, Erv) 586 a.Nbody = list1(n.Right) // if i==nil { goto l } 587 n.Right = a 588 589 case caseKindTypeVar, caseKindTypeConst: 590 n.Right = s.typeone(n) 591 } 592 } 593 594 // generate list of if statements, binary search for constant sequences 595 for len(cc) > 0 { 596 if cc[0].typ != caseKindTypeConst { 597 n := cc[0].node 598 cas = list(cas, n.Right) 599 cc = cc[1:] 600 continue 601 } 602 603 // identify run of constants 604 var run int 605 for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ { 606 } 607 608 // sort by hash 609 sort.Sort(caseClauseByType(cc[:run])) 610 611 // for debugging: linear search 612 if false { 613 for i := 0; i < run; i++ { 614 n := cc[i].node 615 cas = list(cas, n.Right) 616 } 617 continue 618 } 619 620 // combine adjacent cases with the same hash 621 ncase := 0 622 for i := 0; i < run; i++ { 623 ncase++ 624 hash := list1(cc[i].node.Right) 625 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ { 626 hash = list(hash, cc[j].node.Right) 627 } 628 cc[i].node.Right = liststmt(hash) 629 } 630 631 // binary search among cases to narrow by hash 632 cas = list(cas, s.walkCases(cc[:ncase])) 633 cc = cc[ncase:] 634 } 635 636 // handle default case 637 if nerrors == 0 { 638 cas = list(cas, def) 639 sw.Nbody = concat(cas, sw.Nbody) 640 sw.List = nil 641 walkstmtlist(sw.Nbody) 642 } 643 } 644 645 // typeone generates an AST that jumps to the 646 // case body if the variable is of type t. 647 func (s *typeSwitch) typeone(t *Node) *Node { 648 var name *Node 649 var init *NodeList 650 if t.Rlist == nil { 651 name = nblank 652 typecheck(&nblank, Erv|Easgn) 653 } else { 654 name = t.Rlist.N 655 init = list1(Nod(ODCL, name, nil)) 656 a := Nod(OAS, name, nil) 657 typecheck(&a, Etop) 658 init = list(init, a) 659 } 660 661 a := Nod(OAS2, nil, nil) 662 a.List = list(list1(name), s.okname) // name, ok = 663 b := Nod(ODOTTYPE, s.facename, nil) 664 b.Type = t.Left.Type // interface.(type) 665 a.Rlist = list1(b) 666 typecheck(&a, Etop) 667 init = list(init, a) 668 669 c := Nod(OIF, nil, nil) 670 c.Left = s.okname 671 c.Nbody = list1(t.Right) // if ok { goto l } 672 673 return liststmt(list(init, c)) 674 } 675 676 // walkCases generates an AST implementing the cases in cc. 677 func (s *typeSwitch) walkCases(cc []*caseClause) *Node { 678 if len(cc) < binarySearchMin { 679 var cas *NodeList 680 for _, c := range cc { 681 n := c.node 682 if c.typ != caseKindTypeConst { 683 Fatalf("typeSwitch walkCases") 684 } 685 a := Nod(OIF, nil, nil) 686 a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash))) 687 typecheck(&a.Left, Erv) 688 a.Nbody = list1(n.Right) 689 cas = list(cas, a) 690 } 691 return liststmt(cas) 692 } 693 694 // find the middle and recur 695 half := len(cc) / 2 696 a := Nod(OIF, nil, nil) 697 a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash))) 698 typecheck(&a.Left, Erv) 699 a.Nbody = list1(s.walkCases(cc[:half])) 700 a.Rlist = list1(s.walkCases(cc[half:])) 701 return a 702 } 703 704 type caseClauseByOrd []*caseClause 705 706 func (x caseClauseByOrd) Len() int { return len(x) } 707 func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 708 func (x caseClauseByOrd) Less(i, j int) bool { 709 c1, c2 := x[i], x[j] 710 switch { 711 // sort default first 712 case c1.typ == caseKindDefault: 713 return true 714 case c2.typ == caseKindDefault: 715 return false 716 717 // sort nil second 718 case c1.typ == caseKindTypeNil: 719 return true 720 case c2.typ == caseKindTypeNil: 721 return false 722 } 723 724 // sort by ordinal 725 return c1.ordinal < c2.ordinal 726 } 727 728 type caseClauseByExpr []*caseClause 729 730 func (x caseClauseByExpr) Len() int { return len(x) } 731 func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 732 func (x caseClauseByExpr) Less(i, j int) bool { 733 return exprcmp(x[i], x[j]) < 0 734 } 735 736 func exprcmp(c1, c2 *caseClause) int { 737 // sort non-constants last 738 if c1.typ != caseKindExprConst { 739 return +1 740 } 741 if c2.typ != caseKindExprConst { 742 return -1 743 } 744 745 n1 := c1.node.Left 746 n2 := c2.node.Left 747 748 // sort by type (for switches on interface) 749 ct := n1.Val().Ctype() 750 if ct > n2.Val().Ctype() { 751 return +1 752 } 753 if ct < n2.Val().Ctype() { 754 return -1 755 } 756 if !Eqtype(n1.Type, n2.Type) { 757 if n1.Type.Vargen > n2.Type.Vargen { 758 return +1 759 } else { 760 return -1 761 } 762 } 763 764 // sort by constant value to enable binary search 765 switch ct { 766 case CTFLT: 767 return mpcmpfltflt(n1.Val().U.(*Mpflt), n2.Val().U.(*Mpflt)) 768 case CTINT, CTRUNE: 769 return Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint)) 770 case CTSTR: 771 // Sort strings by length and then by value. 772 // It is much cheaper to compare lengths than values, 773 // and all we need here is consistency. 774 // We respect this sorting in exprSwitch.walkCases. 775 a := n1.Val().U.(string) 776 b := n2.Val().U.(string) 777 if len(a) < len(b) { 778 return -1 779 } 780 if len(a) > len(b) { 781 return +1 782 } 783 if a == b { 784 return 0 785 } 786 if a < b { 787 return -1 788 } 789 return +1 790 } 791 792 return 0 793 } 794 795 type caseClauseByType []*caseClause 796 797 func (x caseClauseByType) Len() int { return len(x) } 798 func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 799 func (x caseClauseByType) Less(i, j int) bool { 800 c1, c2 := x[i], x[j] 801 switch { 802 // sort non-constants last 803 case c1.typ != caseKindTypeConst: 804 return false 805 case c2.typ != caseKindTypeConst: 806 return true 807 808 // sort by hash code 809 case c1.hash != c2.hash: 810 return c1.hash < c2.hash 811 } 812 813 // sort by ordinal 814 return c1.ordinal < c2.ordinal 815 }