github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 "sort" 8 9 const ( 10 // expression switch 11 switchKindExpr = iota // switch a {...} or switch 5 {...} 12 switchKindTrue // switch true {...} or switch {...} 13 switchKindFalse // switch false {...} 14 ) 15 16 const ( 17 binarySearchMin = 4 // minimum number of cases for binary search 18 integerRangeMin = 2 // minimum size of integer ranges 19 ) 20 21 // An exprSwitch walks an expression switch. 22 type exprSwitch struct { 23 exprname *Node // node for the expression being switched on 24 kind int // kind of switch statement (switchKind*) 25 } 26 27 // A typeSwitch walks a type switch. 28 type typeSwitch struct { 29 hashname *Node // node for the hash of the type of the variable being switched on 30 facename *Node // node for the concrete type of the variable being switched on 31 okname *Node // boolean node used for comma-ok type assertions 32 } 33 34 // A caseClause is a single case clause in a switch statement. 35 type caseClause struct { 36 node *Node // points at case statement 37 ordinal int // position in switch 38 hash uint32 // hash of a type switch 39 // isconst indicates whether this case clause is a constant, 40 // for the purposes of the switch code generation. 41 // For expression switches, that's generally literals (case 5:, not case x:). 42 // For type switches, that's concrete types (case time.Time:), not interfaces (case io.Reader:). 43 isconst bool 44 } 45 46 // caseClauses are all the case clauses in a switch statement. 47 type caseClauses struct { 48 list []caseClause // general cases 49 defjmp *Node // OGOTO for default case or OBREAK if no default case present 50 niljmp *Node // OGOTO for nil type case in a type switch 51 } 52 53 // typecheckswitch typechecks a switch statement. 54 func typecheckswitch(n *Node) { 55 lno := lineno 56 typecheckslice(n.Ninit.Slice(), Etop) 57 58 var nilonly string 59 var top int 60 var t *Type 61 62 if n.Left != nil && n.Left.Op == OTYPESW { 63 // type switch 64 top = Etype 65 n.Left.Right = typecheck(n.Left.Right, Erv) 66 t = n.Left.Right.Type 67 if t != nil && !t.IsInterface() { 68 yyerror("cannot type switch on non-interface value %L", n.Left.Right) 69 } 70 } else { 71 // expression switch 72 top = Erv 73 if n.Left != nil { 74 n.Left = typecheck(n.Left, Erv) 75 n.Left = defaultlit(n.Left, nil) 76 t = n.Left.Type 77 } else { 78 t = Types[TBOOL] 79 } 80 if t != nil { 81 switch { 82 case !okforeq[t.Etype]: 83 yyerror("cannot switch on %L", n.Left) 84 case t.IsSlice(): 85 nilonly = "slice" 86 case t.IsArray() && !t.IsComparable(): 87 yyerror("cannot switch on %L", n.Left) 88 case t.IsStruct(): 89 if f := t.IncomparableField(); f != nil { 90 yyerror("cannot switch on %L (struct containing %v cannot be compared)", n.Left, f.Type) 91 } 92 case t.Etype == TFUNC: 93 nilonly = "func" 94 case t.IsMap(): 95 nilonly = "map" 96 } 97 } 98 } 99 100 n.Type = t 101 102 var def, niltype *Node 103 for _, ncase := range n.List.Slice() { 104 setlineno(n) 105 if ncase.List.Len() == 0 { 106 // default 107 if def != nil { 108 setlineno(ncase) 109 yyerror("multiple defaults in switch (first at %v)", def.Line()) 110 } else { 111 def = ncase 112 } 113 } else { 114 ls := ncase.List.Slice() 115 for i1, n1 := range ls { 116 setlineno(n1) 117 ls[i1] = typecheck(ls[i1], Erv|Etype) 118 n1 = ls[i1] 119 if n1.Type == nil || t == nil { 120 continue 121 } 122 setlineno(ncase) 123 switch top { 124 // expression switch 125 case Erv: 126 ls[i1] = defaultlit(ls[i1], t) 127 n1 = ls[i1] 128 switch { 129 case n1.Op == OTYPE: 130 yyerror("type %v is not an expression", n1.Type) 131 case n1.Type != nil && assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0: 132 if n.Left != nil { 133 yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t) 134 } else { 135 yyerror("invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type) 136 } 137 case nilonly != "" && !isnil(n1): 138 yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left) 139 case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable(): 140 yyerror("invalid case %L in switch (incomparable type)", n1) 141 } 142 143 // type switch 144 case Etype: 145 var missing, have *Field 146 var ptr int 147 switch { 148 case n1.Op == OLITERAL && n1.Type.IsKind(TNIL): 149 // case nil: 150 if niltype != nil { 151 yyerror("multiple nil cases in type switch (first at %v)", niltype.Line()) 152 } else { 153 niltype = ncase 154 } 155 case n1.Op != OTYPE && n1.Type != nil: // should this be ||? 156 yyerror("%L is not a type", n1) 157 // reset to original type 158 n1 = n.Left.Right 159 ls[i1] = n1 160 case !n1.Type.IsInterface() && t.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr): 161 if have != nil && !missing.Broke && !have.Broke { 162 yyerror("impossible type switch case: %L cannot have dynamic type %v"+ 163 " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", n.Left.Right, n1.Type, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) 164 } else if !missing.Broke { 165 yyerror("impossible type switch case: %L cannot have dynamic type %v"+ 166 " (missing %v method)", n.Left.Right, n1.Type, missing.Sym) 167 } 168 } 169 } 170 } 171 } 172 173 if top == Etype && n.Type != nil { 174 ll := ncase.List 175 if ncase.Rlist.Len() != 0 { 176 nvar := ncase.Rlist.First() 177 if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) { 178 // single entry type switch 179 nvar.Name.Param.Ntype = typenod(ll.First().Type) 180 } else { 181 // multiple entry type switch or default 182 nvar.Name.Param.Ntype = typenod(n.Type) 183 } 184 185 nvar = typecheck(nvar, Erv|Easgn) 186 ncase.Rlist.SetIndex(0, nvar) 187 } 188 } 189 190 typecheckslice(ncase.Nbody.Slice(), Etop) 191 } 192 193 lineno = lno 194 } 195 196 // walkswitch walks a switch statement. 197 func walkswitch(sw *Node) { 198 // convert switch {...} to switch true {...} 199 if sw.Left == nil { 200 sw.Left = nodbool(true) 201 sw.Left = typecheck(sw.Left, Erv) 202 } 203 204 if sw.Left.Op == OTYPESW { 205 var s typeSwitch 206 s.walk(sw) 207 } else { 208 var s exprSwitch 209 s.walk(sw) 210 } 211 } 212 213 // walk generates an AST implementing sw. 214 // sw is an expression switch. 215 // The AST is generally of the form of a linear 216 // search using if..goto, although binary search 217 // is used with long runs of constants. 218 func (s *exprSwitch) walk(sw *Node) { 219 casebody(sw, nil) 220 221 cond := sw.Left 222 sw.Left = nil 223 224 s.kind = switchKindExpr 225 if Isconst(cond, CTBOOL) { 226 s.kind = switchKindTrue 227 if !cond.Val().U.(bool) { 228 s.kind = switchKindFalse 229 } 230 } 231 232 cond = walkexpr(cond, &sw.Ninit) 233 t := sw.Type 234 if t == nil { 235 return 236 } 237 238 // convert the switch into OIF statements 239 var cas []*Node 240 if s.kind == switchKindTrue || s.kind == switchKindFalse { 241 s.exprname = nodbool(s.kind == switchKindTrue) 242 } else if consttype(cond) >= 0 { 243 // leave constants to enable dead code elimination (issue 9608) 244 s.exprname = cond 245 } else { 246 s.exprname = temp(cond.Type) 247 cas = []*Node{nod(OAS, s.exprname, cond)} 248 typecheckslice(cas, Etop) 249 } 250 251 // Enumerate the cases and prepare the default case. 252 clauses := s.genCaseClauses(sw.List.Slice()) 253 sw.List.Set(nil) 254 cc := clauses.list 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].isconst { 260 a := s.walkCases(cc[:1]) 261 cas = append(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].isconst; run++ { 269 } 270 271 // sort and compile constants 272 sort.Sort(caseClauseByConstVal(cc[:run])) 273 a := s.walkCases(cc[:run]) 274 cas = append(cas, a) 275 cc = cc[run:] 276 } 277 278 // handle default case 279 if nerrors == 0 { 280 cas = append(cas, clauses.defjmp) 281 sw.Nbody.Prepend(cas...) 282 walkstmtlist(sw.Nbody.Slice()) 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 []*Node 291 for _, c := range cc { 292 n := c.node 293 lno := setlineno(n) 294 295 a := nod(OIF, nil, nil) 296 if rng := n.List.Slice(); rng != nil { 297 // Integer range. 298 // exprname is a temp or a constant, 299 // so it is safe to evaluate twice. 300 // In most cases, this conjunction will be 301 // rewritten by walkinrange into a single comparison. 302 low := nod(OGE, s.exprname, rng[0]) 303 high := nod(OLE, s.exprname, rng[1]) 304 a.Left = nod(OANDAND, low, high) 305 a.Left = typecheck(a.Left, Erv) 306 a.Left = walkexpr(a.Left, nil) // give walk the opportunity to optimize the range check 307 } else 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 { 308 a.Left = nod(OEQ, s.exprname, n.Left) // if name == val 309 a.Left = typecheck(a.Left, Erv) 310 } else if s.kind == switchKindTrue { 311 a.Left = n.Left // if val 312 } else { 313 // s.kind == switchKindFalse 314 a.Left = nod(ONOT, n.Left, nil) // if !val 315 a.Left = typecheck(a.Left, Erv) 316 } 317 a.Nbody.Set1(n.Right) // goto l 318 319 cas = append(cas, a) 320 lineno = lno 321 } 322 return liststmt(cas) 323 } 324 325 // find the middle and recur 326 half := len(cc) / 2 327 a := nod(OIF, nil, nil) 328 n := cc[half-1].node 329 var mid *Node 330 if rng := n.List.Slice(); rng != nil { 331 mid = rng[1] // high end of range 332 } else { 333 mid = n.Left 334 } 335 le := nod(OLE, s.exprname, mid) 336 if Isconst(mid, CTSTR) { 337 // Search by length and then by value; see caseClauseByConstVal. 338 lenlt := nod(OLT, nod(OLEN, s.exprname, nil), nod(OLEN, mid, nil)) 339 leneq := nod(OEQ, nod(OLEN, s.exprname, nil), nod(OLEN, mid, nil)) 340 a.Left = nod(OOROR, lenlt, nod(OANDAND, leneq, le)) 341 } else { 342 a.Left = le 343 } 344 a.Left = typecheck(a.Left, Erv) 345 a.Nbody.Set1(s.walkCases(cc[:half])) 346 a.Rlist.Set1(s.walkCases(cc[half:])) 347 return a 348 } 349 350 // casebody builds separate lists of statements and cases. 351 // It makes labels between cases and statements 352 // and deals with fallthrough, break, and unreachable statements. 353 func casebody(sw *Node, typeswvar *Node) { 354 if sw.List.Len() == 0 { 355 return 356 } 357 358 lno := setlineno(sw) 359 360 var cas []*Node // cases 361 var stat []*Node // statements 362 var def *Node // defaults 363 br := nod(OBREAK, nil, nil) 364 365 for i, n := range sw.List.Slice() { 366 setlineno(n) 367 if n.Op != OXCASE { 368 Fatalf("casebody %v", n.Op) 369 } 370 n.Op = OCASE 371 needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL 372 373 jmp := nod(OGOTO, autolabel(".s"), nil) 374 switch n.List.Len() { 375 case 0: 376 // default 377 if def != nil { 378 yyerror("more than one default case") 379 } 380 // reuse original default case 381 n.Right = jmp 382 def = n 383 case 1: 384 // one case -- reuse OCASE node 385 n.Left = n.List.First() 386 n.Right = jmp 387 n.List.Set(nil) 388 cas = append(cas, n) 389 default: 390 // Expand multi-valued cases and detect ranges of integer cases. 391 if typeswvar != nil || sw.Left.Type.IsInterface() || !n.List.First().Type.IsInteger() || n.List.Len() < integerRangeMin { 392 // Can't use integer ranges. Expand each case into a separate node. 393 for _, n1 := range n.List.Slice() { 394 cas = append(cas, nod(OCASE, n1, jmp)) 395 } 396 break 397 } 398 // Find integer ranges within runs of constants. 399 s := n.List.Slice() 400 j := 0 401 for j < len(s) { 402 // Find a run of constants. 403 var run int 404 for run = j; run < len(s) && Isconst(s[run], CTINT); run++ { 405 } 406 if run-j >= integerRangeMin { 407 // Search for integer ranges in s[j:run]. 408 // Typechecking is done, so all values are already in an appropriate range. 409 search := s[j:run] 410 sort.Sort(constIntNodesByVal(search)) 411 for beg, end := 0, 1; end <= len(search); end++ { 412 if end < len(search) && search[end].Int64() == search[end-1].Int64()+1 { 413 continue 414 } 415 if end-beg >= integerRangeMin { 416 // Record range in List. 417 c := nod(OCASE, nil, jmp) 418 c.List.Set2(search[beg], search[end-1]) 419 cas = append(cas, c) 420 } else { 421 // Not large enough for range; record separately. 422 for _, n := range search[beg:end] { 423 cas = append(cas, nod(OCASE, n, jmp)) 424 } 425 } 426 beg = end 427 } 428 j = run 429 } 430 // Advance to next constant, adding individual non-constant 431 // or as-yet-unhandled constant cases as we go. 432 for ; j < len(s) && (j < run || !Isconst(s[j], CTINT)); j++ { 433 cas = append(cas, nod(OCASE, s[j], jmp)) 434 } 435 } 436 } 437 438 stat = append(stat, nod(OLABEL, jmp.Left, nil)) 439 if typeswvar != nil && needvar && n.Rlist.Len() != 0 { 440 l := []*Node{ 441 nod(ODCL, n.Rlist.First(), nil), 442 nod(OAS, n.Rlist.First(), typeswvar), 443 } 444 typecheckslice(l, Etop) 445 stat = append(stat, l...) 446 } 447 stat = append(stat, n.Nbody.Slice()...) 448 449 // Search backwards for the index of the fallthrough 450 // statement. Do not assume it'll be in the last 451 // position, since in some cases (e.g. when the statement 452 // list contains autotmp_ variables), one or more OVARKILL 453 // nodes will be at the end of the list. 454 fallIndex := len(stat) - 1 455 for stat[fallIndex].Op == OVARKILL { 456 fallIndex-- 457 } 458 last := stat[fallIndex] 459 460 // botch - shouldn't fall through declaration 461 if last.Xoffset == n.Xoffset && last.Op == OXFALL { 462 if typeswvar != nil { 463 setlineno(last) 464 yyerror("cannot fallthrough in type switch") 465 } 466 467 if i+1 >= sw.List.Len() { 468 setlineno(last) 469 yyerror("cannot fallthrough final case in switch") 470 } 471 472 last.Op = OFALL 473 } else { 474 stat = append(stat, br) 475 } 476 } 477 478 stat = append(stat, br) 479 if def != nil { 480 cas = append(cas, def) 481 } 482 483 sw.List.Set(cas) 484 sw.Nbody.Set(stat) 485 lineno = lno 486 } 487 488 // genCaseClauses generates the caseClauses value for clauses. 489 func (s *exprSwitch) genCaseClauses(clauses []*Node) caseClauses { 490 var cc caseClauses 491 for _, n := range clauses { 492 if n.Left == nil && n.List.Len() == 0 { 493 // default case 494 if cc.defjmp != nil { 495 Fatalf("duplicate default case not detected during typechecking") 496 } 497 cc.defjmp = n.Right 498 continue 499 } 500 c := caseClause{node: n, ordinal: len(cc.list)} 501 if n.List.Len() > 0 { 502 c.isconst = true 503 } 504 switch consttype(n.Left) { 505 case CTFLT, CTINT, CTRUNE, CTSTR: 506 c.isconst = true 507 } 508 cc.list = append(cc.list, c) 509 } 510 511 if cc.defjmp == nil { 512 cc.defjmp = nod(OBREAK, nil, nil) 513 } 514 515 // diagnose duplicate cases 516 s.checkDupCases(cc.list) 517 return cc 518 } 519 520 // genCaseClauses generates the caseClauses value for clauses. 521 func (s *typeSwitch) genCaseClauses(clauses []*Node) caseClauses { 522 var cc caseClauses 523 for _, n := range clauses { 524 switch { 525 case n.Left == nil: 526 // default case 527 if cc.defjmp != nil { 528 Fatalf("duplicate default case not detected during typechecking") 529 } 530 cc.defjmp = n.Right 531 continue 532 case n.Left.Op == OLITERAL: 533 // nil case in type switch 534 if cc.niljmp != nil { 535 Fatalf("duplicate nil case not detected during typechecking") 536 } 537 cc.niljmp = n.Right 538 continue 539 } 540 541 // general case 542 c := caseClause{ 543 node: n, 544 ordinal: len(cc.list), 545 isconst: !n.Left.Type.IsInterface(), 546 hash: typehash(n.Left.Type), 547 } 548 cc.list = append(cc.list, c) 549 } 550 551 if cc.defjmp == nil { 552 cc.defjmp = nod(OBREAK, nil, nil) 553 } 554 555 // diagnose duplicate cases 556 s.checkDupCases(cc.list) 557 return cc 558 } 559 560 func (s *typeSwitch) checkDupCases(cc []caseClause) { 561 if len(cc) < 2 { 562 return 563 } 564 // We store seen types in a map keyed by type hash. 565 // It is possible, but very unlikely, for multiple distinct types to have the same hash. 566 seen := make(map[uint32][]*Node) 567 // To avoid many small allocations of length 1 slices, 568 // also set up a single large slice to slice into. 569 nn := make([]*Node, 0, len(cc)) 570 Outer: 571 for _, c := range cc { 572 prev, ok := seen[c.hash] 573 if !ok { 574 // First entry for this hash. 575 nn = append(nn, c.node) 576 seen[c.hash] = nn[len(nn)-1 : len(nn):len(nn)] 577 continue 578 } 579 for _, n := range prev { 580 if eqtype(n.Left.Type, c.node.Left.Type) { 581 yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line()) 582 // avoid double-reporting errors 583 continue Outer 584 } 585 } 586 seen[c.hash] = append(seen[c.hash], c.node) 587 } 588 } 589 590 func (s *exprSwitch) checkDupCases(cc []caseClause) { 591 if len(cc) < 2 { 592 return 593 } 594 // The common case is that s's expression is not an interface. 595 // In that case, all constant clauses have the same type, 596 // so checking for duplicates can be done solely by value. 597 if !s.exprname.Type.IsInterface() { 598 seen := make(map[interface{}]*Node) 599 for _, c := range cc { 600 switch { 601 case c.node.Left != nil: 602 // Single constant. 603 604 // Can't check for duplicates that aren't constants, per the spec. Issue 15896. 605 // Don't check for duplicate bools. Although the spec allows it, 606 // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and 607 // (2) it would disallow useful things like 608 // case GOARCH == "arm" && GOARM == "5": 609 // case GOARCH == "arm": 610 // which would both evaluate to false for non-ARM compiles. 611 if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL { 612 continue 613 } 614 615 val := c.node.Left.Val().Interface() 616 prev, dup := seen[val] 617 if !dup { 618 seen[val] = c.node 619 continue 620 } 621 setlineno(c.node) 622 yyerror("duplicate case %#v in switch\n\tprevious case at %v", val, prev.Line()) 623 624 case c.node.List.Len() == 2: 625 // Range of integers. 626 low := c.node.List.Index(0).Int64() 627 high := c.node.List.Index(1).Int64() 628 for i := low; i <= high; i++ { 629 prev, dup := seen[i] 630 if !dup { 631 seen[i] = c.node 632 continue 633 } 634 setlineno(c.node) 635 yyerror("duplicate case %d in switch\n\tprevious case at %v", i, prev.Line()) 636 } 637 638 default: 639 Fatalf("bad caseClause node in checkDupCases: %v", c.node) 640 } 641 } 642 return 643 } 644 // s's expression is an interface. This is fairly rare, so keep this simple. 645 // Duplicates are only duplicates if they have the same type and the same value. 646 type typeVal struct { 647 typ string 648 val interface{} 649 } 650 seen := make(map[typeVal]*Node) 651 for _, c := range cc { 652 if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL { 653 continue 654 } 655 n := c.node.Left 656 tv := typeVal{ 657 // n.Type.tconv(FmtLeft | FmtUnsigned) here serves to completely describe the type. 658 // See the comments in func typehash. 659 typ: n.Type.tconv(FmtLeft | FmtUnsigned), 660 val: n.Val().Interface(), 661 } 662 prev, dup := seen[tv] 663 if !dup { 664 seen[tv] = c.node 665 continue 666 } 667 setlineno(c.node) 668 yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line()) 669 } 670 } 671 672 // walk generates an AST that implements sw, 673 // where sw is a type switch. 674 // The AST is generally of the form of a linear 675 // search using if..goto, although binary search 676 // is used with long runs of concrete types. 677 func (s *typeSwitch) walk(sw *Node) { 678 cond := sw.Left 679 sw.Left = nil 680 681 if cond == nil { 682 sw.List.Set(nil) 683 return 684 } 685 if cond.Right == nil { 686 setlineno(sw) 687 yyerror("type switch must have an assignment") 688 return 689 } 690 691 cond.Right = walkexpr(cond.Right, &sw.Ninit) 692 if !cond.Right.Type.IsInterface() { 693 yyerror("type switch must be on an interface") 694 return 695 } 696 697 var cas []*Node 698 699 // predeclare temporary variables and the boolean var 700 s.facename = temp(cond.Right.Type) 701 702 a := nod(OAS, s.facename, cond.Right) 703 a = typecheck(a, Etop) 704 cas = append(cas, a) 705 706 s.okname = temp(Types[TBOOL]) 707 s.okname = typecheck(s.okname, Erv) 708 709 s.hashname = temp(Types[TUINT32]) 710 s.hashname = typecheck(s.hashname, Erv) 711 712 // set up labels and jumps 713 casebody(sw, s.facename) 714 715 clauses := s.genCaseClauses(sw.List.Slice()) 716 sw.List.Set(nil) 717 def := clauses.defjmp 718 719 // For empty interfaces, do: 720 // if e._type == nil { 721 // do nil case if it exists, otherwise default 722 // } 723 // h := e._type.hash 724 // Use a similar strategy for non-empty interfaces. 725 726 // Get interface descriptor word. 727 typ := nod(OITAB, s.facename, nil) 728 729 // Check for nil first. 730 i := nod(OIF, nil, nil) 731 i.Left = nod(OEQ, typ, nodnil()) 732 if clauses.niljmp != nil { 733 // Do explicit nil case right here. 734 i.Nbody.Set1(clauses.niljmp) 735 } else { 736 // Jump to default case. 737 lbl := autolabel(".s") 738 i.Nbody.Set1(nod(OGOTO, lbl, nil)) 739 // Wrap default case with label. 740 blk := nod(OBLOCK, nil, nil) 741 blk.List.Set([]*Node{nod(OLABEL, lbl, nil), def}) 742 def = blk 743 } 744 i.Left = typecheck(i.Left, Erv) 745 cas = append(cas, i) 746 747 if !cond.Right.Type.IsEmptyInterface() { 748 // Load type from itab. 749 typ = itabType(typ) 750 } 751 // Load hash from type. 752 h := nodSym(ODOTPTR, typ, nil) 753 h.Type = Types[TUINT32] 754 h.Typecheck = 1 755 h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type 756 h.Bounded = true // guaranteed not to fault 757 a = nod(OAS, s.hashname, h) 758 a = typecheck(a, Etop) 759 cas = append(cas, a) 760 761 cc := clauses.list 762 763 // insert type equality check into each case block 764 for _, c := range cc { 765 c.node.Right = s.typeone(c.node) 766 } 767 768 // generate list of if statements, binary search for constant sequences 769 for len(cc) > 0 { 770 if !cc[0].isconst { 771 n := cc[0].node 772 cas = append(cas, n.Right) 773 cc = cc[1:] 774 continue 775 } 776 777 // identify run of constants 778 var run int 779 for run = 1; run < len(cc) && cc[run].isconst; run++ { 780 } 781 782 // sort by hash 783 sort.Sort(caseClauseByType(cc[:run])) 784 785 // for debugging: linear search 786 if false { 787 for i := 0; i < run; i++ { 788 n := cc[i].node 789 cas = append(cas, n.Right) 790 } 791 continue 792 } 793 794 // combine adjacent cases with the same hash 795 ncase := 0 796 for i := 0; i < run; i++ { 797 ncase++ 798 hash := []*Node{cc[i].node.Right} 799 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ { 800 hash = append(hash, cc[j].node.Right) 801 } 802 cc[i].node.Right = liststmt(hash) 803 } 804 805 // binary search among cases to narrow by hash 806 cas = append(cas, s.walkCases(cc[:ncase])) 807 cc = cc[ncase:] 808 } 809 810 // handle default case 811 if nerrors == 0 { 812 cas = append(cas, def) 813 sw.Nbody.Prepend(cas...) 814 sw.List.Set(nil) 815 walkstmtlist(sw.Nbody.Slice()) 816 } 817 } 818 819 // typeone generates an AST that jumps to the 820 // case body if the variable is of type t. 821 func (s *typeSwitch) typeone(t *Node) *Node { 822 var name *Node 823 var init []*Node 824 if t.Rlist.Len() == 0 { 825 name = nblank 826 nblank = typecheck(nblank, Erv|Easgn) 827 } else { 828 name = t.Rlist.First() 829 init = []*Node{nod(ODCL, name, nil)} 830 a := nod(OAS, name, nil) 831 a = typecheck(a, Etop) 832 init = append(init, a) 833 } 834 835 a := nod(OAS2, nil, nil) 836 a.List.Set([]*Node{name, s.okname}) // name, ok = 837 b := nod(ODOTTYPE, s.facename, nil) 838 b.Type = t.Left.Type // interface.(type) 839 a.Rlist.Set1(b) 840 a = typecheck(a, Etop) 841 init = append(init, a) 842 843 c := nod(OIF, nil, nil) 844 c.Left = s.okname 845 c.Nbody.Set1(t.Right) // if ok { goto l } 846 847 return liststmt(append(init, c)) 848 } 849 850 // walkCases generates an AST implementing the cases in cc. 851 func (s *typeSwitch) walkCases(cc []caseClause) *Node { 852 if len(cc) < binarySearchMin { 853 var cas []*Node 854 for _, c := range cc { 855 n := c.node 856 if !c.isconst { 857 Fatalf("typeSwitch walkCases") 858 } 859 a := nod(OIF, nil, nil) 860 a.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) 861 a.Left = typecheck(a.Left, Erv) 862 a.Nbody.Set1(n.Right) 863 cas = append(cas, a) 864 } 865 return liststmt(cas) 866 } 867 868 // find the middle and recur 869 half := len(cc) / 2 870 a := nod(OIF, nil, nil) 871 a.Left = nod(OLE, s.hashname, nodintconst(int64(cc[half-1].hash))) 872 a.Left = typecheck(a.Left, Erv) 873 a.Nbody.Set1(s.walkCases(cc[:half])) 874 a.Rlist.Set1(s.walkCases(cc[half:])) 875 return a 876 } 877 878 // caseClauseByConstVal sorts clauses by constant value to enable binary search. 879 type caseClauseByConstVal []caseClause 880 881 func (x caseClauseByConstVal) Len() int { return len(x) } 882 func (x caseClauseByConstVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 883 func (x caseClauseByConstVal) Less(i, j int) bool { 884 // n1 and n2 might be individual constants or integer ranges. 885 // We have checked for duplicates already, 886 // so ranges can be safely represented by any value in the range. 887 n1 := x[i].node 888 var v1 interface{} 889 if s := n1.List.Slice(); s != nil { 890 v1 = s[0].Val().U 891 } else { 892 v1 = n1.Left.Val().U 893 } 894 895 n2 := x[j].node 896 var v2 interface{} 897 if s := n2.List.Slice(); s != nil { 898 v2 = s[0].Val().U 899 } else { 900 v2 = n2.Left.Val().U 901 } 902 903 switch v1 := v1.(type) { 904 case *Mpflt: 905 return v1.Cmp(v2.(*Mpflt)) < 0 906 case *Mpint: 907 return v1.Cmp(v2.(*Mpint)) < 0 908 case string: 909 // Sort strings by length and then by value. 910 // It is much cheaper to compare lengths than values, 911 // and all we need here is consistency. 912 // We respect this sorting in exprSwitch.walkCases. 913 a := v1 914 b := v2.(string) 915 if len(a) != len(b) { 916 return len(a) < len(b) 917 } 918 return a < b 919 } 920 921 Fatalf("caseClauseByConstVal passed bad clauses %v < %v", x[i].node.Left, x[j].node.Left) 922 return false 923 } 924 925 type caseClauseByType []caseClause 926 927 func (x caseClauseByType) Len() int { return len(x) } 928 func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 929 func (x caseClauseByType) Less(i, j int) bool { 930 c1, c2 := x[i], x[j] 931 // sort by hash code, then ordinal (for the rare case of hash collisions) 932 if c1.hash != c2.hash { 933 return c1.hash < c2.hash 934 } 935 return c1.ordinal < c2.ordinal 936 } 937 938 type constIntNodesByVal []*Node 939 940 func (x constIntNodesByVal) Len() int { return len(x) } 941 func (x constIntNodesByVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 942 func (x constIntNodesByVal) Less(i, j int) bool { 943 return x[i].Val().U.(*Mpint).Cmp(x[j].Val().U.(*Mpint)) < 0 944 }