github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 binarySearchMin = 4 // minimum number of cases for binary search 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 %v", Nconv(n.Left.Right, FmtLong)) 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 %v", Nconv(n.Left, FmtLong)) 84 case t.IsSlice(): 85 nilonly = "slice" 86 case t.IsArray() && !t.IsComparable(): 87 Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong)) 88 case t.IsStruct(): 89 if f := t.IncomparableField(); f != nil { 90 Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), 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 %v in switch (incomparable type)", Nconv(n1, FmtLong)) 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("%v is not a type", Nconv(n1, FmtLong)) 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: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym, have.Sym, Tconv(have.Type, FmtShort), missing.Sym, Tconv(missing.Type, FmtShort)) 163 } else if !missing.Broke { 164 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym) 165 } 166 } 167 } 168 } 169 } 170 171 if top == Etype && n.Type != nil { 172 ll := ncase.List 173 if ncase.Rlist.Len() != 0 { 174 nvar := ncase.Rlist.First() 175 if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) { 176 // single entry type switch 177 nvar.Name.Param.Ntype = typenod(ll.First().Type) 178 } else { 179 // multiple entry type switch or default 180 nvar.Name.Param.Ntype = typenod(n.Type) 181 } 182 183 nvar = typecheck(nvar, Erv|Easgn) 184 ncase.Rlist.SetIndex(0, nvar) 185 } 186 } 187 188 typecheckslice(ncase.Nbody.Slice(), Etop) 189 } 190 191 lineno = lno 192 } 193 194 // walkswitch walks a switch statement. 195 func walkswitch(sw *Node) { 196 // convert switch {...} to switch true {...} 197 if sw.Left == nil { 198 sw.Left = Nodbool(true) 199 sw.Left = typecheck(sw.Left, Erv) 200 } 201 202 if sw.Left.Op == OTYPESW { 203 var s typeSwitch 204 s.walk(sw) 205 } else { 206 var s exprSwitch 207 s.walk(sw) 208 } 209 } 210 211 // walk generates an AST implementing sw. 212 // sw is an expression switch. 213 // The AST is generally of the form of a linear 214 // search using if..goto, although binary search 215 // is used with long runs of constants. 216 func (s *exprSwitch) walk(sw *Node) { 217 casebody(sw, nil) 218 219 cond := sw.Left 220 sw.Left = nil 221 222 s.kind = switchKindExpr 223 if Isconst(cond, CTBOOL) { 224 s.kind = switchKindTrue 225 if !cond.Val().U.(bool) { 226 s.kind = switchKindFalse 227 } 228 } 229 230 cond = walkexpr(cond, &sw.Ninit) 231 t := sw.Type 232 if t == nil { 233 return 234 } 235 236 // convert the switch into OIF statements 237 var cas []*Node 238 if s.kind == switchKindTrue || s.kind == switchKindFalse { 239 s.exprname = Nodbool(s.kind == switchKindTrue) 240 } else if consttype(cond) >= 0 { 241 // leave constants to enable dead code elimination (issue 9608) 242 s.exprname = cond 243 } else { 244 s.exprname = temp(cond.Type) 245 cas = []*Node{Nod(OAS, s.exprname, cond)} 246 typecheckslice(cas, Etop) 247 } 248 249 // Enumerate the cases and prepare the default case. 250 clauses := s.genCaseClauses(sw.List.Slice()) 251 sw.List.Set(nil) 252 cc := clauses.list 253 254 // handle the cases in order 255 for len(cc) > 0 { 256 // deal with expressions one at a time 257 if !okforcmp[t.Etype] || !cc[0].isconst { 258 a := s.walkCases(cc[:1]) 259 cas = append(cas, a) 260 cc = cc[1:] 261 continue 262 } 263 264 // do binary search on runs of constants 265 var run int 266 for run = 1; run < len(cc) && cc[run].isconst; run++ { 267 } 268 269 // sort and compile constants 270 sort.Sort(caseClauseByConstVal(cc[:run])) 271 a := s.walkCases(cc[:run]) 272 cas = append(cas, a) 273 cc = cc[run:] 274 } 275 276 // handle default case 277 if nerrors == 0 { 278 cas = append(cas, clauses.defjmp) 279 sw.Nbody.Set(append(cas, sw.Nbody.Slice()...)) 280 walkstmtlist(sw.Nbody.Slice()) 281 } 282 } 283 284 // walkCases generates an AST implementing the cases in cc. 285 func (s *exprSwitch) walkCases(cc []caseClause) *Node { 286 if len(cc) < binarySearchMin { 287 // linear search 288 var cas []*Node 289 for _, c := range cc { 290 n := c.node 291 lno := setlineno(n) 292 293 a := Nod(OIF, nil, nil) 294 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 { 295 a.Left = Nod(OEQ, s.exprname, n.Left) // if name == val 296 a.Left = typecheck(a.Left, Erv) 297 } else if s.kind == switchKindTrue { 298 a.Left = n.Left // if val 299 } else { 300 // s.kind == switchKindFalse 301 a.Left = Nod(ONOT, n.Left, nil) // if !val 302 a.Left = typecheck(a.Left, Erv) 303 } 304 a.Nbody.Set1(n.Right) // goto l 305 306 cas = append(cas, a) 307 lineno = lno 308 } 309 return liststmt(cas) 310 } 311 312 // find the middle and recur 313 half := len(cc) / 2 314 a := Nod(OIF, nil, nil) 315 mid := cc[half-1].node.Left 316 le := Nod(OLE, s.exprname, mid) 317 if Isconst(mid, CTSTR) { 318 // Search by length and then by value; see caseClauseByConstVal. 319 lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil)) 320 leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil)) 321 a.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le)) 322 } else { 323 a.Left = le 324 } 325 a.Left = typecheck(a.Left, Erv) 326 a.Nbody.Set1(s.walkCases(cc[:half])) 327 a.Rlist.Set1(s.walkCases(cc[half:])) 328 return a 329 } 330 331 // casebody builds separate lists of statements and cases. 332 // It makes labels between cases and statements 333 // and deals with fallthrough, break, and unreachable statements. 334 func casebody(sw *Node, typeswvar *Node) { 335 if sw.List.Len() == 0 { 336 return 337 } 338 339 lno := setlineno(sw) 340 341 var cas []*Node // cases 342 var stat []*Node // statements 343 var def *Node // defaults 344 br := Nod(OBREAK, nil, nil) 345 346 for i, n := range sw.List.Slice() { 347 setlineno(n) 348 if n.Op != OXCASE { 349 Fatalf("casebody %v", n.Op) 350 } 351 n.Op = OCASE 352 needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL 353 354 jmp := Nod(OGOTO, autolabel(".s"), nil) 355 switch n.List.Len() { 356 case 0: 357 // default 358 if def != nil { 359 Yyerror("more than one default case") 360 } 361 // reuse original default case 362 n.Right = jmp 363 def = n 364 case 1: 365 // one case -- reuse OCASE node 366 n.Left = n.List.First() 367 n.Right = jmp 368 n.List.Set(nil) 369 cas = append(cas, n) 370 default: 371 // expand multi-valued cases 372 for _, n1 := range n.List.Slice() { 373 cas = append(cas, Nod(OCASE, n1, jmp)) 374 } 375 } 376 377 stat = append(stat, Nod(OLABEL, jmp.Left, nil)) 378 if typeswvar != nil && needvar && n.Rlist.Len() != 0 { 379 l := []*Node{ 380 Nod(ODCL, n.Rlist.First(), nil), 381 Nod(OAS, n.Rlist.First(), typeswvar), 382 } 383 typecheckslice(l, Etop) 384 stat = append(stat, l...) 385 } 386 stat = append(stat, n.Nbody.Slice()...) 387 388 // botch - shouldn't fall through declaration 389 last := stat[len(stat)-1] 390 if last.Xoffset == n.Xoffset && last.Op == OXFALL { 391 if typeswvar != nil { 392 setlineno(last) 393 Yyerror("cannot fallthrough in type switch") 394 } 395 396 if i+1 >= sw.List.Len() { 397 setlineno(last) 398 Yyerror("cannot fallthrough final case in switch") 399 } 400 401 last.Op = OFALL 402 } else { 403 stat = append(stat, br) 404 } 405 } 406 407 stat = append(stat, br) 408 if def != nil { 409 cas = append(cas, def) 410 } 411 412 sw.List.Set(cas) 413 sw.Nbody.Set(stat) 414 lineno = lno 415 } 416 417 // genCaseClauses generates the caseClauses value for clauses. 418 func (s *exprSwitch) genCaseClauses(clauses []*Node) caseClauses { 419 var cc caseClauses 420 for _, n := range clauses { 421 if n.Left == nil { 422 // default case 423 if cc.defjmp != nil { 424 Fatalf("duplicate default case not detected during typechecking") 425 } 426 cc.defjmp = n.Right 427 continue 428 } 429 c := caseClause{node: n, ordinal: len(cc.list)} 430 switch consttype(n.Left) { 431 case CTFLT, CTINT, CTRUNE, CTSTR: 432 c.isconst = true 433 } 434 cc.list = append(cc.list, c) 435 } 436 437 if cc.defjmp == nil { 438 cc.defjmp = Nod(OBREAK, nil, nil) 439 } 440 441 // diagnose duplicate cases 442 s.checkDupCases(cc.list) 443 return cc 444 } 445 446 // genCaseClauses generates the caseClauses value for clauses. 447 func (s *typeSwitch) genCaseClauses(clauses []*Node) caseClauses { 448 var cc caseClauses 449 for _, n := range clauses { 450 switch { 451 case n.Left == nil: 452 // default case 453 if cc.defjmp != nil { 454 Fatalf("duplicate default case not detected during typechecking") 455 } 456 cc.defjmp = n.Right 457 continue 458 case n.Left.Op == OLITERAL: 459 // nil case in type switch 460 if cc.niljmp != nil { 461 Fatalf("duplicate nil case not detected during typechecking") 462 } 463 cc.niljmp = n.Right 464 continue 465 } 466 467 // general case 468 c := caseClause{ 469 node: n, 470 ordinal: len(cc.list), 471 isconst: !n.Left.Type.IsInterface(), 472 hash: typehash(n.Left.Type), 473 } 474 cc.list = append(cc.list, c) 475 } 476 477 if cc.defjmp == nil { 478 cc.defjmp = Nod(OBREAK, nil, nil) 479 } 480 481 // diagnose duplicate cases 482 s.checkDupCases(cc.list) 483 return cc 484 } 485 486 func (s *typeSwitch) checkDupCases(cc []caseClause) { 487 if len(cc) < 2 { 488 return 489 } 490 // We store seen types in a map keyed by type hash. 491 // It is possible, but very unlikely, for multiple distinct types to have the same hash. 492 seen := make(map[uint32][]*Node) 493 // To avoid many small allocations of length 1 slices, 494 // also set up a single large slice to slice into. 495 nn := make([]*Node, 0, len(cc)) 496 Outer: 497 for _, c := range cc { 498 prev, ok := seen[c.hash] 499 if !ok { 500 // First entry for this hash. 501 nn = append(nn, c.node) 502 seen[c.hash] = nn[len(nn)-1 : len(nn):len(nn)] 503 continue 504 } 505 for _, n := range prev { 506 if Eqtype(n.Left.Type, c.node.Left.Type) { 507 yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line()) 508 // avoid double-reporting errors 509 continue Outer 510 } 511 } 512 seen[c.hash] = append(seen[c.hash], c.node) 513 } 514 } 515 516 func (s *exprSwitch) checkDupCases(cc []caseClause) { 517 if len(cc) < 2 { 518 return 519 } 520 // The common case is that s's expression is not an interface. 521 // In that case, all constant clauses have the same type, 522 // so checking for duplicates can be done solely by value. 523 if !s.exprname.Type.IsInterface() { 524 seen := make(map[interface{}]*Node) 525 for _, c := range cc { 526 // Can't check for duplicates that aren't constants, per the spec. Issue 15896. 527 // Don't check for duplicate bools. Although the spec allows it, 528 // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and 529 // (2) it would disallow useful things like 530 // case GOARCH == "arm" && GOARM == "5": 531 // case GOARCH == "arm": 532 // which would both evaluate to false for non-ARM compiles. 533 if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL { 534 continue 535 } 536 val := c.node.Left.Val().Interface() 537 prev, dup := seen[val] 538 if !dup { 539 seen[val] = c.node 540 continue 541 } 542 setlineno(c.node) 543 Yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line()) 544 } 545 return 546 } 547 // s's expression is an interface. This is fairly rare, so keep this simple. 548 // Duplicates are only duplicates if they have the same type and the same value. 549 type typeVal struct { 550 typ string 551 val interface{} 552 } 553 seen := make(map[typeVal]*Node) 554 for _, c := range cc { 555 if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL { 556 continue 557 } 558 n := c.node.Left 559 tv := typeVal{ 560 // Tconv here serves to completely describe the type. 561 // See the comments in func typehash. 562 typ: Tconv(n.Type, FmtLeft|FmtUnsigned), 563 val: n.Val().Interface(), 564 } 565 prev, dup := seen[tv] 566 if !dup { 567 seen[tv] = c.node 568 continue 569 } 570 setlineno(c.node) 571 Yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line()) 572 } 573 } 574 575 // walk generates an AST that implements sw, 576 // where sw is a type switch. 577 // The AST is generally of the form of a linear 578 // search using if..goto, although binary search 579 // is used with long runs of concrete types. 580 func (s *typeSwitch) walk(sw *Node) { 581 cond := sw.Left 582 sw.Left = nil 583 584 if cond == nil { 585 sw.List.Set(nil) 586 return 587 } 588 if cond.Right == nil { 589 setlineno(sw) 590 Yyerror("type switch must have an assignment") 591 return 592 } 593 594 cond.Right = walkexpr(cond.Right, &sw.Ninit) 595 if !cond.Right.Type.IsInterface() { 596 Yyerror("type switch must be on an interface") 597 return 598 } 599 600 var cas []*Node 601 602 // predeclare temporary variables and the boolean var 603 s.facename = temp(cond.Right.Type) 604 605 a := Nod(OAS, s.facename, cond.Right) 606 a = typecheck(a, Etop) 607 cas = append(cas, a) 608 609 s.okname = temp(Types[TBOOL]) 610 s.okname = typecheck(s.okname, Erv) 611 612 s.hashname = temp(Types[TUINT32]) 613 s.hashname = typecheck(s.hashname, Erv) 614 615 // set up labels and jumps 616 casebody(sw, s.facename) 617 618 clauses := s.genCaseClauses(sw.List.Slice()) 619 sw.List.Set(nil) 620 def := clauses.defjmp 621 622 // For empty interfaces, do: 623 // if e._type == nil { 624 // do nil case if it exists, otherwise default 625 // } 626 // h := e._type.hash 627 // Use a similar strategy for non-empty interfaces. 628 629 // Get interface descriptor word. 630 typ := Nod(OITAB, s.facename, nil) 631 632 // Check for nil first. 633 i := Nod(OIF, nil, nil) 634 i.Left = Nod(OEQ, typ, nodnil()) 635 if clauses.niljmp != nil { 636 // Do explicit nil case right here. 637 i.Nbody.Set1(clauses.niljmp) 638 } else { 639 // Jump to default case. 640 lbl := autolabel(".s") 641 i.Nbody.Set1(Nod(OGOTO, lbl, nil)) 642 // Wrap default case with label. 643 blk := Nod(OBLOCK, nil, nil) 644 blk.List.Set([]*Node{Nod(OLABEL, lbl, nil), def}) 645 def = blk 646 } 647 i.Left = typecheck(i.Left, Erv) 648 cas = append(cas, i) 649 650 if !cond.Right.Type.IsEmptyInterface() { 651 // Load type from itab. 652 typ = itabType(typ) 653 } 654 // Load hash from type. 655 h := NodSym(ODOTPTR, typ, nil) 656 h.Type = Types[TUINT32] 657 h.Typecheck = 1 658 h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type 659 h.Bounded = true // guaranteed not to fault 660 a = Nod(OAS, s.hashname, h) 661 a = typecheck(a, Etop) 662 cas = append(cas, a) 663 664 cc := clauses.list 665 666 // insert type equality check into each case block 667 for _, c := range cc { 668 c.node.Right = s.typeone(c.node) 669 } 670 671 // generate list of if statements, binary search for constant sequences 672 for len(cc) > 0 { 673 if !cc[0].isconst { 674 n := cc[0].node 675 cas = append(cas, n.Right) 676 cc = cc[1:] 677 continue 678 } 679 680 // identify run of constants 681 var run int 682 for run = 1; run < len(cc) && cc[run].isconst; run++ { 683 } 684 685 // sort by hash 686 sort.Sort(caseClauseByType(cc[:run])) 687 688 // for debugging: linear search 689 if false { 690 for i := 0; i < run; i++ { 691 n := cc[i].node 692 cas = append(cas, n.Right) 693 } 694 continue 695 } 696 697 // combine adjacent cases with the same hash 698 ncase := 0 699 for i := 0; i < run; i++ { 700 ncase++ 701 hash := []*Node{cc[i].node.Right} 702 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ { 703 hash = append(hash, cc[j].node.Right) 704 } 705 cc[i].node.Right = liststmt(hash) 706 } 707 708 // binary search among cases to narrow by hash 709 cas = append(cas, s.walkCases(cc[:ncase])) 710 cc = cc[ncase:] 711 } 712 713 // handle default case 714 if nerrors == 0 { 715 cas = append(cas, def) 716 sw.Nbody.Set(append(cas, sw.Nbody.Slice()...)) 717 sw.List.Set(nil) 718 walkstmtlist(sw.Nbody.Slice()) 719 } 720 } 721 722 // typeone generates an AST that jumps to the 723 // case body if the variable is of type t. 724 func (s *typeSwitch) typeone(t *Node) *Node { 725 var name *Node 726 var init []*Node 727 if t.Rlist.Len() == 0 { 728 name = nblank 729 nblank = typecheck(nblank, Erv|Easgn) 730 } else { 731 name = t.Rlist.First() 732 init = []*Node{Nod(ODCL, name, nil)} 733 a := Nod(OAS, name, nil) 734 a = typecheck(a, Etop) 735 init = append(init, a) 736 } 737 738 a := Nod(OAS2, nil, nil) 739 a.List.Set([]*Node{name, s.okname}) // name, ok = 740 b := Nod(ODOTTYPE, s.facename, nil) 741 b.Type = t.Left.Type // interface.(type) 742 a.Rlist.Set1(b) 743 a = typecheck(a, Etop) 744 init = append(init, a) 745 746 c := Nod(OIF, nil, nil) 747 c.Left = s.okname 748 c.Nbody.Set1(t.Right) // if ok { goto l } 749 750 return liststmt(append(init, c)) 751 } 752 753 // walkCases generates an AST implementing the cases in cc. 754 func (s *typeSwitch) walkCases(cc []caseClause) *Node { 755 if len(cc) < binarySearchMin { 756 var cas []*Node 757 for _, c := range cc { 758 n := c.node 759 if !c.isconst { 760 Fatalf("typeSwitch walkCases") 761 } 762 a := Nod(OIF, nil, nil) 763 a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash))) 764 a.Left = typecheck(a.Left, Erv) 765 a.Nbody.Set1(n.Right) 766 cas = append(cas, a) 767 } 768 return liststmt(cas) 769 } 770 771 // find the middle and recur 772 half := len(cc) / 2 773 a := Nod(OIF, nil, nil) 774 a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash))) 775 a.Left = typecheck(a.Left, Erv) 776 a.Nbody.Set1(s.walkCases(cc[:half])) 777 a.Rlist.Set1(s.walkCases(cc[half:])) 778 return a 779 } 780 781 // caseClauseByConstVal sorts clauses by constant value to enable binary search. 782 type caseClauseByConstVal []caseClause 783 784 func (x caseClauseByConstVal) Len() int { return len(x) } 785 func (x caseClauseByConstVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 786 func (x caseClauseByConstVal) Less(i, j int) bool { 787 v1 := x[i].node.Left.Val().U 788 v2 := x[j].node.Left.Val().U 789 790 switch v1 := v1.(type) { 791 case *Mpflt: 792 return v1.Cmp(v2.(*Mpflt)) < 0 793 case *Mpint: 794 return v1.Cmp(v2.(*Mpint)) < 0 795 case string: 796 // Sort strings by length and then by value. 797 // It is much cheaper to compare lengths than values, 798 // and all we need here is consistency. 799 // We respect this sorting in exprSwitch.walkCases. 800 a := v1 801 b := v2.(string) 802 if len(a) != len(b) { 803 return len(a) < len(b) 804 } 805 return a < b 806 } 807 808 Fatalf("caseClauseByConstVal passed bad clauses %v < %v", x[i].node.Left, x[j].node.Left) 809 return false 810 } 811 812 type caseClauseByType []caseClause 813 814 func (x caseClauseByType) Len() int { return len(x) } 815 func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 816 func (x caseClauseByType) Less(i, j int) bool { 817 c1, c2 := x[i], x[j] 818 // sort by hash code, then ordinal (for the rare case of hash collisions) 819 if c1.hash != c2.hash { 820 return c1.hash < c2.hash 821 } 822 return c1.ordinal < c2.ordinal 823 }