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