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