github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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 "fmt" 10 "sort" 11 "strconv" 12 ) 13 14 const ( 15 // expression switch 16 switchKindExpr = iota // switch a {...} or switch 5 {...} 17 switchKindTrue // switch true {...} or switch {...} 18 switchKindFalse // switch false {...} 19 20 // type switch 21 switchKindType // switch a.(type) {...} 22 ) 23 24 const ( 25 caseKindDefault = iota // default: 26 27 // expression switch 28 caseKindExprConst // case 5: 29 caseKindExprVar // case x: 30 31 // type switch 32 caseKindTypeNil // case nil: 33 caseKindTypeConst // case time.Time: (concrete type, has type hash) 34 caseKindTypeVar // case io.Reader: (interface type) 35 ) 36 37 const binarySearchMin = 4 // minimum number of cases for binary search 38 39 // An exprSwitch walks an expression switch. 40 type exprSwitch struct { 41 exprname *Node // node for the expression being switched on 42 kind int // kind of switch statement (switchKind*) 43 } 44 45 // A typeSwitch walks a type switch. 46 type typeSwitch struct { 47 hashname *Node // node for the hash of the type of the variable being switched on 48 facename *Node // node for the concrete type of the variable being switched on 49 okname *Node // boolean node used for comma-ok type assertions 50 } 51 52 // A caseClause is a single case clause in a switch statement. 53 type caseClause struct { 54 node *Node // points at case statement 55 ordinal int // position in switch 56 hash uint32 // hash of a type switch 57 typ uint8 // type of case 58 } 59 60 // typecheckswitch typechecks a switch statement. 61 func typecheckswitch(n *Node) { 62 lno := int(lineno) 63 typechecklist(n.Ninit, Etop) 64 65 var nilonly string 66 var top int 67 var t *Type 68 69 if n.Ntest != nil && n.Ntest.Op == OTYPESW { 70 // type switch 71 top = Etype 72 typecheck(&n.Ntest.Right, Erv) 73 t = n.Ntest.Right.Type 74 if t != nil && t.Etype != TINTER { 75 Yyerror("cannot type switch on non-interface value %v", Nconv(n.Ntest.Right, obj.FmtLong)) 76 } 77 } else { 78 // expression switch 79 top = Erv 80 if n.Ntest != nil { 81 typecheck(&n.Ntest, Erv) 82 defaultlit(&n.Ntest, nil) 83 t = n.Ntest.Type 84 } else { 85 t = Types[TBOOL] 86 } 87 if t != nil { 88 var badtype *Type 89 switch { 90 case !okforeq[t.Etype]: 91 Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong)) 92 case t.Etype == TARRAY && !Isfixedarray(t): 93 nilonly = "slice" 94 case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ: 95 Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong)) 96 case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ: 97 Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), Tconv(badtype, 0)) 98 case t.Etype == TFUNC: 99 nilonly = "func" 100 case t.Etype == TMAP: 101 nilonly = "map" 102 } 103 } 104 } 105 106 n.Type = t 107 108 var def *Node 109 var ll *NodeList 110 for l := n.List; l != nil; l = l.Next { 111 ncase := l.N 112 setlineno(n) 113 if ncase.List == nil { 114 // default 115 if def != nil { 116 Yyerror("multiple defaults in switch (first at %v)", def.Line()) 117 } else { 118 def = ncase 119 } 120 } else { 121 for ll = ncase.List; ll != nil; ll = ll.Next { 122 setlineno(ll.N) 123 typecheck(&ll.N, Erv|Etype) 124 if ll.N.Type == nil || t == nil { 125 continue 126 } 127 setlineno(ncase) 128 switch top { 129 // expression switch 130 case Erv: 131 defaultlit(&ll.N, t) 132 switch { 133 case ll.N.Op == OTYPE: 134 Yyerror("type %v is not an expression", Tconv(ll.N.Type, 0)) 135 case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0: 136 if n.Ntest != nil { 137 Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", Nconv(ll.N, 0), Nconv(n.Ntest, 0), Tconv(ll.N.Type, 0), Tconv(t, 0)) 138 } else { 139 Yyerror("invalid case %v in switch (mismatched types %v and bool)", Nconv(ll.N, 0), Tconv(ll.N.Type, 0)) 140 } 141 case nilonly != "" && !Isconst(ll.N, CTNIL): 142 Yyerror("invalid case %v in switch (can only compare %s %v to nil)", Nconv(ll.N, 0), nilonly, Nconv(n.Ntest, 0)) 143 } 144 145 // type switch 146 case Etype: 147 var missing, have *Type 148 var ptr int 149 switch { 150 case ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL): 151 case ll.N.Op != OTYPE && ll.N.Type != nil: // should this be ||? 152 Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong)) 153 // reset to original type 154 ll.N = n.Ntest.Right 155 case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr): 156 if have != nil && missing.Broke == 0 && have.Broke == 0 { 157 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.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort)) 158 } else if missing.Broke == 0 { 159 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0)) 160 } 161 } 162 } 163 } 164 } 165 166 if top == Etype && n.Type != nil { 167 ll = ncase.List 168 nvar := ncase.Nname 169 if nvar != nil { 170 if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) { 171 // single entry type switch 172 nvar.Ntype = typenod(ll.N.Type) 173 } else { 174 // multiple entry type switch or default 175 nvar.Ntype = typenod(n.Type) 176 } 177 178 typecheck(&nvar, Erv|Easgn) 179 ncase.Nname = nvar 180 } 181 } 182 183 typechecklist(ncase.Nbody, Etop) 184 } 185 186 lineno = int32(lno) 187 } 188 189 // walkswitch walks a switch statement. 190 func walkswitch(sw *Node) { 191 // convert switch {...} to switch true {...} 192 if sw.Ntest == nil { 193 sw.Ntest = Nodbool(true) 194 typecheck(&sw.Ntest, Erv) 195 } 196 197 if sw.Ntest.Op == OTYPESW { 198 var s typeSwitch 199 s.walk(sw) 200 } else { 201 var s exprSwitch 202 s.walk(sw) 203 } 204 205 // Discard old AST elements. They can confuse racewalk. 206 sw.Ntest = nil 207 sw.List = nil 208 } 209 210 // walk generates an AST implementing sw. 211 // sw is an expression switch. 212 // The AST is generally of the form of a linear 213 // search using if..goto, although binary search 214 // is used with long runs of constants. 215 func (s *exprSwitch) walk(sw *Node) { 216 casebody(sw, nil) 217 218 s.kind = switchKindExpr 219 if Isconst(sw.Ntest, CTBOOL) { 220 s.kind = switchKindTrue 221 if !sw.Ntest.Val.U.Bval { 222 s.kind = switchKindFalse 223 } 224 } 225 226 walkexpr(&sw.Ntest, &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(sw.Ntest) >= 0 { 237 // leave constants to enable dead code elimination (issue 9608) 238 s.exprname = sw.Ntest 239 } else { 240 s.exprname = temp(sw.Ntest.Type) 241 cas = list1(Nod(OAS, s.exprname, sw.Ntest)) 242 typechecklist(cas, Etop) 243 } 244 245 // enumerate the cases, and lop off the default case 246 cc := caseClauses(sw, s.kind) 247 var def *Node 248 if len(cc) > 0 && cc[0].typ == caseKindDefault { 249 def = cc[0].node.Right 250 cc = cc[1:] 251 } else { 252 def = Nod(OBREAK, nil, nil) 253 } 254 255 // handle the cases in order 256 for len(cc) > 0 { 257 // deal with expressions one at a time 258 if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst { 259 a := s.walkCases(cc[:1]) 260 cas = list(cas, a) 261 cc = cc[1:] 262 continue 263 } 264 265 // do binary search on runs of constants 266 var run int 267 for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ { 268 } 269 270 // sort and compile constants 271 sort.Sort(caseClauseByExpr(cc[:run])) 272 a := s.walkCases(cc[:run]) 273 cas = list(cas, a) 274 cc = cc[run:] 275 } 276 277 // handle default case 278 if nerrors == 0 { 279 cas = list(cas, def) 280 sw.Nbody = concat(cas, sw.Nbody) 281 sw.List = nil 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.Ntest = Nod(OEQ, s.exprname, n.Left) // if name == val 298 typecheck(&a.Ntest, Erv) 299 } else if s.kind == switchKindTrue { 300 a.Ntest = n.Left // if val 301 } else { 302 // s.kind == switchKindFalse 303 a.Ntest = Nod(ONOT, n.Left, nil) // if !val 304 typecheck(&a.Ntest, 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.Ntest = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le)) 324 } else { 325 a.Ntest = le 326 } 327 typecheck(&a.Ntest, Erv) 328 a.Nbody = list1(s.walkCases(cc[:half])) 329 a.Nelse = 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 Fatal("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.Nname != nil { 382 l := list1(Nod(ODCL, n.Nname, nil)) 383 l = list(l, Nod(OAS, n.Nname, 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", Tconv(c2.node.Left.Type, 0), 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", Nconv(c1.node.Left, 0), 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 if sw.Ntest == nil { 516 return 517 } 518 if sw.Ntest.Right == nil { 519 setlineno(sw) 520 Yyerror("type switch must have an assignment") 521 return 522 } 523 524 walkexpr(&sw.Ntest.Right, &sw.Ninit) 525 if !Istype(sw.Ntest.Right.Type, TINTER) { 526 Yyerror("type switch must be on an interface") 527 return 528 } 529 530 var cas *NodeList 531 532 // predeclare temporary variables and the boolean var 533 s.facename = temp(sw.Ntest.Right.Type) 534 535 a := Nod(OAS, s.facename, sw.Ntest.Right) 536 typecheck(&a, Etop) 537 cas = list(cas, a) 538 539 s.okname = temp(Types[TBOOL]) 540 typecheck(&s.okname, Erv) 541 542 s.hashname = temp(Types[TUINT32]) 543 typecheck(&s.hashname, Erv) 544 545 // set up labels and jumps 546 casebody(sw, s.facename) 547 548 // calculate type hash 549 t := sw.Ntest.Right.Type 550 if isnilinter(t) { 551 a = syslook("efacethash", 1) 552 } else { 553 a = syslook("ifacethash", 1) 554 } 555 substArgTypes(a, t) 556 a = Nod(OCALL, a, nil) 557 a.List = list1(s.facename) 558 a = Nod(OAS, s.hashname, a) 559 typecheck(&a, Etop) 560 cas = list(cas, a) 561 562 cc := caseClauses(sw, switchKindType) 563 var def *Node 564 if len(cc) > 0 && cc[0].typ == caseKindDefault { 565 def = cc[0].node.Right 566 cc = cc[1:] 567 } else { 568 def = Nod(OBREAK, nil, nil) 569 } 570 571 // insert type equality check into each case block 572 for _, c := range cc { 573 n := c.node 574 switch c.typ { 575 case caseKindTypeNil: 576 var v Val 577 v.Ctype = CTNIL 578 a = Nod(OIF, nil, nil) 579 a.Ntest = Nod(OEQ, s.facename, nodlit(v)) 580 typecheck(&a.Ntest, Erv) 581 a.Nbody = list1(n.Right) // if i==nil { goto l } 582 n.Right = a 583 584 case caseKindTypeVar, caseKindTypeConst: 585 n.Right = s.typeone(n) 586 } 587 } 588 589 // generate list of if statements, binary search for constant sequences 590 for len(cc) > 0 { 591 if cc[0].typ != caseKindTypeConst { 592 n := cc[0].node 593 cas = list(cas, n.Right) 594 cc = cc[1:] 595 continue 596 } 597 598 // identify run of constants 599 var run int 600 for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ { 601 } 602 603 // sort by hash 604 sort.Sort(caseClauseByType(cc[:run])) 605 606 // for debugging: linear search 607 if false { 608 for i := 0; i < run; i++ { 609 n := cc[i].node 610 cas = list(cas, n.Right) 611 } 612 continue 613 } 614 615 // combine adjacent cases with the same hash 616 ncase := 0 617 for i := 0; i < run; i++ { 618 ncase++ 619 hash := list1(cc[i].node.Right) 620 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ { 621 hash = list(hash, cc[j].node.Right) 622 } 623 cc[i].node.Right = liststmt(hash) 624 } 625 626 // binary search among cases to narrow by hash 627 cas = list(cas, s.walkCases(cc[:ncase])) 628 cc = cc[ncase:] 629 } 630 631 // handle default case 632 if nerrors == 0 { 633 cas = list(cas, def) 634 sw.Nbody = concat(cas, sw.Nbody) 635 sw.List = nil 636 walkstmtlist(sw.Nbody) 637 } 638 } 639 640 // typeone generates an AST that jumps to the 641 // case body if the variable is of type t. 642 func (s *typeSwitch) typeone(t *Node) *Node { 643 name := t.Nname 644 var init *NodeList 645 if name == nil { 646 typecheck(&nblank, Erv|Easgn) 647 name = nblank 648 } else { 649 init = list1(Nod(ODCL, name, nil)) 650 } 651 652 a := Nod(OAS2, nil, nil) 653 a.List = list(list1(name), s.okname) // name, ok = 654 b := Nod(ODOTTYPE, s.facename, nil) 655 b.Type = t.Left.Type // interface.(type) 656 a.Rlist = list1(b) 657 typecheck(&a, Etop) 658 init = list(init, a) 659 660 c := Nod(OIF, nil, nil) 661 c.Ntest = s.okname 662 c.Nbody = list1(t.Right) // if ok { goto l } 663 664 return liststmt(list(init, c)) 665 } 666 667 // walkCases generates an AST implementing the cases in cc. 668 func (s *typeSwitch) walkCases(cc []*caseClause) *Node { 669 if len(cc) < binarySearchMin { 670 var cas *NodeList 671 for _, c := range cc { 672 n := c.node 673 if c.typ != caseKindTypeConst { 674 Fatal("typeSwitch walkCases") 675 } 676 a := Nod(OIF, nil, nil) 677 a.Ntest = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash))) 678 typecheck(&a.Ntest, Erv) 679 a.Nbody = list1(n.Right) 680 cas = list(cas, a) 681 } 682 return liststmt(cas) 683 } 684 685 // find the middle and recur 686 half := len(cc) / 2 687 a := Nod(OIF, nil, nil) 688 a.Ntest = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash))) 689 typecheck(&a.Ntest, Erv) 690 a.Nbody = list1(s.walkCases(cc[:half])) 691 a.Nelse = list1(s.walkCases(cc[half:])) 692 return a 693 } 694 695 type caseClauseByOrd []*caseClause 696 697 func (x caseClauseByOrd) Len() int { return len(x) } 698 func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 699 func (x caseClauseByOrd) Less(i, j int) bool { 700 c1, c2 := x[i], x[j] 701 switch { 702 // sort default first 703 case c1.typ == caseKindDefault: 704 return true 705 case c2.typ == caseKindDefault: 706 return false 707 708 // sort nil second 709 case c1.typ == caseKindTypeNil: 710 return true 711 case c2.typ == caseKindTypeNil: 712 return false 713 } 714 715 // sort by ordinal 716 return c1.ordinal < c2.ordinal 717 } 718 719 type caseClauseByExpr []*caseClause 720 721 func (x caseClauseByExpr) Len() int { return len(x) } 722 func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 723 func (x caseClauseByExpr) Less(i, j int) bool { 724 return exprcmp(x[i], x[j]) < 0 725 } 726 727 func exprcmp(c1, c2 *caseClause) int { 728 // sort non-constants last 729 if c1.typ != caseKindExprConst { 730 return +1 731 } 732 if c2.typ != caseKindExprConst { 733 return -1 734 } 735 736 n1 := c1.node.Left 737 n2 := c2.node.Left 738 739 // sort by type (for switches on interface) 740 ct := int(n1.Val.Ctype) 741 if ct > int(n2.Val.Ctype) { 742 return +1 743 } 744 if ct < int(n2.Val.Ctype) { 745 return -1 746 } 747 if !Eqtype(n1.Type, n2.Type) { 748 if n1.Type.Vargen > n2.Type.Vargen { 749 return +1 750 } else { 751 return -1 752 } 753 } 754 755 // sort by constant value to enable binary search 756 switch ct { 757 case CTFLT: 758 return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval) 759 case CTINT, CTRUNE: 760 return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval) 761 case CTSTR: 762 // Sort strings by length and then by value. 763 // It is much cheaper to compare lengths than values, 764 // and all we need here is consistency. 765 // We respect this sorting in exprSwitch.walkCases. 766 a := n1.Val.U.Sval 767 b := n2.Val.U.Sval 768 if len(a) < len(b) { 769 return -1 770 } 771 if len(a) > len(b) { 772 return +1 773 } 774 return stringsCompare(a, b) 775 } 776 777 return 0 778 } 779 780 type caseClauseByType []*caseClause 781 782 func (x caseClauseByType) Len() int { return len(x) } 783 func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 784 func (x caseClauseByType) Less(i, j int) bool { 785 c1, c2 := x[i], x[j] 786 switch { 787 // sort non-constants last 788 case c1.typ != caseKindTypeConst: 789 return false 790 case c2.typ != caseKindTypeConst: 791 return true 792 793 // sort by hash code 794 case c1.hash != c2.hash: 795 return c1.hash < c2.hash 796 } 797 798 // sort by ordinal 799 return c1.ordinal < c2.ordinal 800 } 801 802 func dumpcase(cc []*caseClause) { 803 for _, c := range cc { 804 switch c.typ { 805 case caseKindDefault: 806 fmt.Printf("case-default\n") 807 fmt.Printf("\tord=%d\n", c.ordinal) 808 809 case caseKindExprConst: 810 fmt.Printf("case-exprconst\n") 811 fmt.Printf("\tord=%d\n", c.ordinal) 812 813 case caseKindExprVar: 814 fmt.Printf("case-exprvar\n") 815 fmt.Printf("\tord=%d\n", c.ordinal) 816 fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0)) 817 818 case caseKindTypeNil: 819 fmt.Printf("case-typenil\n") 820 fmt.Printf("\tord=%d\n", c.ordinal) 821 822 case caseKindTypeConst: 823 fmt.Printf("case-typeconst\n") 824 fmt.Printf("\tord=%d\n", c.ordinal) 825 fmt.Printf("\thash=%x\n", c.hash) 826 827 case caseKindTypeVar: 828 fmt.Printf("case-typevar\n") 829 fmt.Printf("\tord=%d\n", c.ordinal) 830 831 default: 832 fmt.Printf("case-???\n") 833 fmt.Printf("\tord=%d\n", c.ordinal) 834 fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0)) 835 fmt.Printf("\thash=%x\n", c.hash) 836 } 837 } 838 839 fmt.Printf("\n") 840 }