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