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