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