github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 9 "github.com/gagliardetto/golang-go/cmd/internal/src" 10 "sort" 11 ) 12 13 // typecheckswitch typechecks a switch statement. 14 func typecheckswitch(n *Node) { 15 typecheckslice(n.Ninit.Slice(), ctxStmt) 16 if n.Left != nil && n.Left.Op == OTYPESW { 17 typecheckTypeSwitch(n) 18 } else { 19 typecheckExprSwitch(n) 20 } 21 } 22 23 func typecheckTypeSwitch(n *Node) { 24 n.Left.Right = typecheck(n.Left.Right, ctxExpr) 25 t := n.Left.Right.Type 26 if t != nil && !t.IsInterface() { 27 yyerrorl(n.Pos, "cannot type switch on non-interface value %L", n.Left.Right) 28 t = nil 29 } 30 31 // We don't actually declare the type switch's guarded 32 // declaration itself. So if there are no cases, we won't 33 // notice that it went unused. 34 if v := n.Left.Left; v != nil && !v.isBlank() && n.List.Len() == 0 { 35 yyerrorl(v.Pos, "%v declared but not used", v.Sym) 36 } 37 38 var defCase, nilCase *Node 39 var ts typeSet 40 for _, ncase := range n.List.Slice() { 41 ls := ncase.List.Slice() 42 if len(ls) == 0 { // default: 43 if defCase != nil { 44 yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line()) 45 } else { 46 defCase = ncase 47 } 48 } 49 50 for i := range ls { 51 ls[i] = typecheck(ls[i], ctxExpr|ctxType) 52 n1 := ls[i] 53 if t == nil || n1.Type == nil { 54 continue 55 } 56 57 var missing, have *types.Field 58 var ptr int 59 switch { 60 case n1.isNil(): // case nil: 61 if nilCase != nil { 62 yyerrorl(ncase.Pos, "multiple nil cases in type switch (first at %v)", nilCase.Line()) 63 } else { 64 nilCase = ncase 65 } 66 case n1.Op != OTYPE: 67 yyerrorl(ncase.Pos, "%L is not a type", n1) 68 case !n1.Type.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr) && !missing.Broke(): 69 if have != nil && !have.Broke() { 70 yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ 71 " (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) 72 } else if ptr != 0 { 73 yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ 74 " (%v method has pointer receiver)", n.Left.Right, n1.Type, missing.Sym) 75 } else { 76 yyerrorl(ncase.Pos, "impossible type switch case: %L cannot have dynamic type %v"+ 77 " (missing %v method)", n.Left.Right, n1.Type, missing.Sym) 78 } 79 } 80 81 if n1.Op == OTYPE { 82 ts.add(ncase.Pos, n1.Type) 83 } 84 } 85 86 if ncase.Rlist.Len() != 0 { 87 // Assign the clause variable's type. 88 vt := t 89 if len(ls) == 1 { 90 if ls[0].Op == OTYPE { 91 vt = ls[0].Type 92 } else if ls[0].Op != OLITERAL { // TODO(mdempsky): Should be !ls[0].isNil() 93 // Invalid single-type case; 94 // mark variable as broken. 95 vt = nil 96 } 97 } 98 99 // TODO(mdempsky): It should be possible to 100 // still typecheck the case body. 101 if vt == nil { 102 continue 103 } 104 105 nvar := ncase.Rlist.First() 106 nvar.Type = vt 107 nvar = typecheck(nvar, ctxExpr|ctxAssign) 108 ncase.Rlist.SetFirst(nvar) 109 } 110 111 typecheckslice(ncase.Nbody.Slice(), ctxStmt) 112 } 113 } 114 115 type typeSet struct { 116 m map[string][]typeSetEntry 117 } 118 119 type typeSetEntry struct { 120 pos src.XPos 121 typ *types.Type 122 } 123 124 func (s *typeSet) add(pos src.XPos, typ *types.Type) { 125 if s.m == nil { 126 s.m = make(map[string][]typeSetEntry) 127 } 128 129 // LongString does not uniquely identify types, so we need to 130 // disambiguate collisions with types.Identical. 131 // TODO(mdempsky): Add a method that *is* unique. 132 ls := typ.LongString() 133 prevs := s.m[ls] 134 for _, prev := range prevs { 135 if types.Identical(typ, prev.typ) { 136 yyerrorl(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, linestr(prev.pos)) 137 return 138 } 139 } 140 s.m[ls] = append(prevs, typeSetEntry{pos, typ}) 141 } 142 143 func typecheckExprSwitch(n *Node) { 144 t := types.Types[TBOOL] 145 if n.Left != nil { 146 n.Left = typecheck(n.Left, ctxExpr) 147 n.Left = defaultlit(n.Left, nil) 148 t = n.Left.Type 149 } 150 151 var nilonly string 152 if t != nil { 153 switch { 154 case t.IsMap(): 155 nilonly = "map" 156 case t.Etype == TFUNC: 157 nilonly = "func" 158 case t.IsSlice(): 159 nilonly = "slice" 160 161 case !IsComparable(t): 162 if t.IsStruct() { 163 yyerrorl(n.Pos, "cannot switch on %L (struct containing %v cannot be compared)", n.Left, IncomparableField(t).Type) 164 } else { 165 yyerrorl(n.Pos, "cannot switch on %L", n.Left) 166 } 167 t = nil 168 } 169 } 170 171 var defCase *Node 172 var cs constSet 173 for _, ncase := range n.List.Slice() { 174 ls := ncase.List.Slice() 175 if len(ls) == 0 { // default: 176 if defCase != nil { 177 yyerrorl(ncase.Pos, "multiple defaults in switch (first at %v)", defCase.Line()) 178 } else { 179 defCase = ncase 180 } 181 } 182 183 for i := range ls { 184 setlineno(ncase) 185 ls[i] = typecheck(ls[i], ctxExpr) 186 ls[i] = defaultlit(ls[i], t) 187 n1 := ls[i] 188 if t == nil || n1.Type == nil { 189 continue 190 } 191 192 switch { 193 case nilonly != "" && !n1.isNil(): 194 yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left) 195 case t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type): 196 yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1) 197 case assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0: 198 if n.Left != nil { 199 yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t) 200 } else { 201 yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type) 202 } 203 } 204 205 // Don't check for duplicate bools. Although the spec allows it, 206 // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and 207 // (2) it would disallow useful things like 208 // case GOARCH == "arm" && GOARM == "5": 209 // case GOARCH == "arm": 210 // which would both evaluate to false for non-ARM compiles. 211 if !n1.Type.IsBoolean() { 212 cs.add(ncase.Pos, n1, "case", "switch") 213 } 214 } 215 216 typecheckslice(ncase.Nbody.Slice(), ctxStmt) 217 } 218 } 219 220 // walkswitch walks a switch statement. 221 func walkswitch(sw *Node) { 222 // Guard against double walk, see #25776. 223 if sw.List.Len() == 0 && sw.Nbody.Len() > 0 { 224 return // Was fatal, but eliminating every possible source of double-walking is hard 225 } 226 227 if sw.Left != nil && sw.Left.Op == OTYPESW { 228 walkTypeSwitch(sw) 229 } else { 230 walkExprSwitch(sw) 231 } 232 } 233 234 // walkExprSwitch generates an AST implementing sw. sw is an 235 // expression switch. 236 func walkExprSwitch(sw *Node) { 237 lno := setlineno(sw) 238 239 cond := sw.Left 240 sw.Left = nil 241 242 // convert switch {...} to switch true {...} 243 if cond == nil { 244 cond = nodbool(true) 245 cond = typecheck(cond, ctxExpr) 246 cond = defaultlit(cond, nil) 247 } 248 249 // Given "switch string(byteslice)", 250 // with all cases being side-effect free, 251 // use a zero-cost alias of the byte slice. 252 // Do this before calling walkexpr on cond, 253 // because walkexpr will lower the string 254 // conversion into a runtime call. 255 // See issue 24937 for more discussion. 256 if cond.Op == OBYTES2STR && allCaseExprsAreSideEffectFree(sw) { 257 cond.Op = OBYTES2STRTMP 258 } 259 260 cond = walkexpr(cond, &sw.Ninit) 261 if cond.Op != OLITERAL { 262 cond = copyexpr(cond, cond.Type, &sw.Nbody) 263 } 264 265 lineno = lno 266 267 s := exprSwitch{ 268 exprname: cond, 269 } 270 271 var defaultGoto *Node 272 var body Nodes 273 for _, ncase := range sw.List.Slice() { 274 label := autolabel(".s") 275 jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) 276 277 // Process case dispatch. 278 if ncase.List.Len() == 0 { 279 if defaultGoto != nil { 280 Fatalf("duplicate default case not detected during typechecking") 281 } 282 defaultGoto = jmp 283 } 284 285 for _, n1 := range ncase.List.Slice() { 286 s.Add(ncase.Pos, n1, jmp) 287 } 288 289 // Process body. 290 body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label))) 291 body.Append(ncase.Nbody.Slice()...) 292 if fall, pos := hasFall(ncase.Nbody.Slice()); !fall { 293 br := nod(OBREAK, nil, nil) 294 br.Pos = pos 295 body.Append(br) 296 } 297 } 298 sw.List.Set(nil) 299 300 if defaultGoto == nil { 301 br := nod(OBREAK, nil, nil) 302 br.Pos = br.Pos.WithNotStmt() 303 defaultGoto = br 304 } 305 306 s.Emit(&sw.Nbody) 307 sw.Nbody.Append(defaultGoto) 308 sw.Nbody.AppendNodes(&body) 309 walkstmtlist(sw.Nbody.Slice()) 310 } 311 312 // An exprSwitch walks an expression switch. 313 type exprSwitch struct { 314 exprname *Node // value being switched on 315 316 done Nodes 317 clauses []exprClause 318 } 319 320 type exprClause struct { 321 pos src.XPos 322 lo, hi *Node 323 jmp *Node 324 } 325 326 func (s *exprSwitch) Add(pos src.XPos, expr, jmp *Node) { 327 c := exprClause{pos: pos, lo: expr, hi: expr, jmp: jmp} 328 if okforcmp[s.exprname.Type.Etype] && expr.Op == OLITERAL { 329 s.clauses = append(s.clauses, c) 330 return 331 } 332 333 s.flush() 334 s.clauses = append(s.clauses, c) 335 s.flush() 336 } 337 338 func (s *exprSwitch) Emit(out *Nodes) { 339 s.flush() 340 out.AppendNodes(&s.done) 341 } 342 343 func (s *exprSwitch) flush() { 344 cc := s.clauses 345 s.clauses = nil 346 if len(cc) == 0 { 347 return 348 } 349 350 // Caution: If len(cc) == 1, then cc[0] might not an OLITERAL. 351 // The code below is structured to implicitly handle this case 352 // (e.g., sort.Slice doesn't need to invoke the less function 353 // when there's only a single slice element). 354 355 if s.exprname.Type.IsString() && len(cc) >= 2 { 356 // Sort strings by length and then by value. It is 357 // much cheaper to compare lengths than values, and 358 // all we need here is consistency. We respect this 359 // sorting below. 360 sort.Slice(cc, func(i, j int) bool { 361 si := strlit(cc[i].lo) 362 sj := strlit(cc[j].lo) 363 if len(si) != len(sj) { 364 return len(si) < len(sj) 365 } 366 return si < sj 367 }) 368 369 // runLen returns the string length associated with a 370 // particular run of exprClauses. 371 runLen := func(run []exprClause) int64 { return int64(len(strlit(run[0].lo))) } 372 373 // Collapse runs of consecutive strings with the same length. 374 var runs [][]exprClause 375 start := 0 376 for i := 1; i < len(cc); i++ { 377 if runLen(cc[start:]) != runLen(cc[i:]) { 378 runs = append(runs, cc[start:i]) 379 start = i 380 } 381 } 382 runs = append(runs, cc[start:]) 383 384 // Perform two-level binary search. 385 nlen := nod(OLEN, s.exprname, nil) 386 binarySearch(len(runs), &s.done, 387 func(i int) *Node { 388 return nod(OLE, nlen, nodintconst(runLen(runs[i-1]))) 389 }, 390 func(i int, nif *Node) { 391 run := runs[i] 392 nif.Left = nod(OEQ, nlen, nodintconst(runLen(run))) 393 s.search(run, &nif.Nbody) 394 }, 395 ) 396 return 397 } 398 399 sort.Slice(cc, func(i, j int) bool { 400 return compareOp(cc[i].lo.Val(), OLT, cc[j].lo.Val()) 401 }) 402 403 // Merge consecutive integer cases. 404 if s.exprname.Type.IsInteger() { 405 merged := cc[:1] 406 for _, c := range cc[1:] { 407 last := &merged[len(merged)-1] 408 if last.jmp == c.jmp && last.hi.Int64()+1 == c.lo.Int64() { 409 last.hi = c.lo 410 } else { 411 merged = append(merged, c) 412 } 413 } 414 cc = merged 415 } 416 417 s.search(cc, &s.done) 418 } 419 420 func (s *exprSwitch) search(cc []exprClause, out *Nodes) { 421 binarySearch(len(cc), out, 422 func(i int) *Node { 423 return nod(OLE, s.exprname, cc[i-1].hi) 424 }, 425 func(i int, nif *Node) { 426 c := &cc[i] 427 nif.Left = c.test(s.exprname) 428 nif.Nbody.Set1(c.jmp) 429 }, 430 ) 431 } 432 433 func (c *exprClause) test(exprname *Node) *Node { 434 // Integer range. 435 if c.hi != c.lo { 436 low := nodl(c.pos, OGE, exprname, c.lo) 437 high := nodl(c.pos, OLE, exprname, c.hi) 438 return nodl(c.pos, OANDAND, low, high) 439 } 440 441 // Optimize "switch true { ...}" and "switch false { ... }". 442 if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() { 443 if exprname.Val().U.(bool) { 444 return c.lo 445 } else { 446 return nodl(c.pos, ONOT, c.lo, nil) 447 } 448 } 449 450 return nodl(c.pos, OEQ, exprname, c.lo) 451 } 452 453 func allCaseExprsAreSideEffectFree(sw *Node) bool { 454 // In theory, we could be more aggressive, allowing any 455 // side-effect-free expressions in cases, but it's a bit 456 // tricky because some of that information is unavailable due 457 // to the introduction of temporaries during order. 458 // Restricting to constants is simple and probably powerful 459 // enough. 460 461 for _, ncase := range sw.List.Slice() { 462 if ncase.Op != OCASE { 463 Fatalf("switch string(byteslice) bad op: %v", ncase.Op) 464 } 465 for _, v := range ncase.List.Slice() { 466 if v.Op != OLITERAL { 467 return false 468 } 469 } 470 } 471 return true 472 } 473 474 // hasFall reports whether stmts ends with a "fallthrough" statement. 475 func hasFall(stmts []*Node) (bool, src.XPos) { 476 // Search backwards for the index of the fallthrough 477 // statement. Do not assume it'll be in the last 478 // position, since in some cases (e.g. when the statement 479 // list contains autotmp_ variables), one or more OVARKILL 480 // nodes will be at the end of the list. 481 482 i := len(stmts) - 1 483 for i >= 0 && stmts[i].Op == OVARKILL { 484 i-- 485 } 486 if i < 0 { 487 return false, src.NoXPos 488 } 489 return stmts[i].Op == OFALL, stmts[i].Pos 490 } 491 492 // walkTypeSwitch generates an AST that implements sw, where sw is a 493 // type switch. 494 func walkTypeSwitch(sw *Node) { 495 var s typeSwitch 496 s.facename = sw.Left.Right 497 sw.Left = nil 498 499 s.facename = walkexpr(s.facename, &sw.Ninit) 500 s.facename = copyexpr(s.facename, s.facename.Type, &sw.Nbody) 501 s.okname = temp(types.Types[TBOOL]) 502 503 // Get interface descriptor word. 504 // For empty interfaces this will be the type. 505 // For non-empty interfaces this will be the itab. 506 itab := nod(OITAB, s.facename, nil) 507 508 // For empty interfaces, do: 509 // if e._type == nil { 510 // do nil case if it exists, otherwise default 511 // } 512 // h := e._type.hash 513 // Use a similar strategy for non-empty interfaces. 514 ifNil := nod(OIF, nil, nil) 515 ifNil.Left = nod(OEQ, itab, nodnil()) 516 lineno = lineno.WithNotStmt() // disable statement marks after the first check. 517 ifNil.Left = typecheck(ifNil.Left, ctxExpr) 518 ifNil.Left = defaultlit(ifNil.Left, nil) 519 // ifNil.Nbody assigned at end. 520 sw.Nbody.Append(ifNil) 521 522 // Load hash from type or itab. 523 dotHash := nodSym(ODOTPTR, itab, nil) 524 dotHash.Type = types.Types[TUINT32] 525 dotHash.SetTypecheck(1) 526 if s.facename.Type.IsEmptyInterface() { 527 dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type 528 } else { 529 dotHash.Xoffset = int64(2 * Widthptr) // offset of hash in runtime.itab 530 } 531 dotHash.SetBounded(true) // guaranteed not to fault 532 s.hashname = copyexpr(dotHash, dotHash.Type, &sw.Nbody) 533 534 br := nod(OBREAK, nil, nil) 535 var defaultGoto, nilGoto *Node 536 var body Nodes 537 for _, ncase := range sw.List.Slice() { 538 var caseVar *Node 539 if ncase.Rlist.Len() != 0 { 540 caseVar = ncase.Rlist.First() 541 } 542 543 // For single-type cases, we initialize the case 544 // variable as part of the type assertion; but in 545 // other cases, we initialize it in the body. 546 singleType := ncase.List.Len() == 1 && ncase.List.First().Op == OTYPE 547 548 label := autolabel(".s") 549 jmp := npos(ncase.Pos, nodSym(OGOTO, nil, label)) 550 551 if ncase.List.Len() == 0 { // default: 552 if defaultGoto != nil { 553 Fatalf("duplicate default case not detected during typechecking") 554 } 555 defaultGoto = jmp 556 } 557 558 for _, n1 := range ncase.List.Slice() { 559 if n1.isNil() { // case nil: 560 if nilGoto != nil { 561 Fatalf("duplicate nil case not detected during typechecking") 562 } 563 nilGoto = jmp 564 continue 565 } 566 567 if singleType { 568 s.Add(n1.Type, caseVar, jmp) 569 } else { 570 s.Add(n1.Type, nil, jmp) 571 } 572 } 573 574 body.Append(npos(ncase.Pos, nodSym(OLABEL, nil, label))) 575 if caseVar != nil && !singleType { 576 l := []*Node{ 577 nodl(ncase.Pos, ODCL, caseVar, nil), 578 nodl(ncase.Pos, OAS, caseVar, s.facename), 579 } 580 typecheckslice(l, ctxStmt) 581 body.Append(l...) 582 } 583 body.Append(ncase.Nbody.Slice()...) 584 body.Append(br) 585 } 586 sw.List.Set(nil) 587 588 if defaultGoto == nil { 589 defaultGoto = br 590 } 591 if nilGoto == nil { 592 nilGoto = defaultGoto 593 } 594 ifNil.Nbody.Set1(nilGoto) 595 596 s.Emit(&sw.Nbody) 597 sw.Nbody.Append(defaultGoto) 598 sw.Nbody.AppendNodes(&body) 599 600 walkstmtlist(sw.Nbody.Slice()) 601 } 602 603 // A typeSwitch walks a type switch. 604 type typeSwitch struct { 605 // Temporary variables (i.e., ONAMEs) used by type switch dispatch logic: 606 facename *Node // value being type-switched on 607 hashname *Node // type hash of the value being type-switched on 608 okname *Node // boolean used for comma-ok type assertions 609 610 done Nodes 611 clauses []typeClause 612 } 613 614 type typeClause struct { 615 hash uint32 616 body Nodes 617 } 618 619 func (s *typeSwitch) Add(typ *types.Type, caseVar *Node, jmp *Node) { 620 var body Nodes 621 if caseVar != nil { 622 l := []*Node{ 623 nod(ODCL, caseVar, nil), 624 nod(OAS, caseVar, nil), 625 } 626 typecheckslice(l, ctxStmt) 627 body.Append(l...) 628 } else { 629 caseVar = nblank 630 } 631 632 // cv, ok = iface.(type) 633 as := nod(OAS2, nil, nil) 634 as.List.Set2(caseVar, s.okname) // cv, ok = 635 dot := nod(ODOTTYPE, s.facename, nil) 636 dot.Type = typ // iface.(type) 637 as.Rlist.Set1(dot) 638 as = typecheck(as, ctxStmt) 639 as = walkexpr(as, &body) 640 body.Append(as) 641 642 // if ok { goto label } 643 nif := nod(OIF, nil, nil) 644 nif.Left = s.okname 645 nif.Nbody.Set1(jmp) 646 body.Append(nif) 647 648 if !typ.IsInterface() { 649 s.clauses = append(s.clauses, typeClause{ 650 hash: typehash(typ), 651 body: body, 652 }) 653 return 654 } 655 656 s.flush() 657 s.done.AppendNodes(&body) 658 } 659 660 func (s *typeSwitch) Emit(out *Nodes) { 661 s.flush() 662 out.AppendNodes(&s.done) 663 } 664 665 func (s *typeSwitch) flush() { 666 cc := s.clauses 667 s.clauses = nil 668 if len(cc) == 0 { 669 return 670 } 671 672 sort.Slice(cc, func(i, j int) bool { return cc[i].hash < cc[j].hash }) 673 674 // Combine adjacent cases with the same hash. 675 merged := cc[:1] 676 for _, c := range cc[1:] { 677 last := &merged[len(merged)-1] 678 if last.hash == c.hash { 679 last.body.AppendNodes(&c.body) 680 } else { 681 merged = append(merged, c) 682 } 683 } 684 cc = merged 685 686 binarySearch(len(cc), &s.done, 687 func(i int) *Node { 688 return nod(OLE, s.hashname, nodintconst(int64(cc[i-1].hash))) 689 }, 690 func(i int, nif *Node) { 691 // TODO(mdempsky): Omit hash equality check if 692 // there's only one type. 693 c := cc[i] 694 nif.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash))) 695 nif.Nbody.AppendNodes(&c.body) 696 }, 697 ) 698 } 699 700 // binarySearch constructs a binary search tree for handling n cases, 701 // and appends it to out. It's used for efficiently implementing 702 // switch statements. 703 // 704 // less(i) should return a boolean expression. If it evaluates true, 705 // then cases before i will be tested; otherwise, cases i and later. 706 // 707 // base(i, nif) should setup nif (an OIF node) to test case i. In 708 // particular, it should set nif.Left and nif.Nbody. 709 func binarySearch(n int, out *Nodes, less func(i int) *Node, base func(i int, nif *Node)) { 710 const binarySearchMin = 4 // minimum number of cases for binary search 711 712 var do func(lo, hi int, out *Nodes) 713 do = func(lo, hi int, out *Nodes) { 714 n := hi - lo 715 if n < binarySearchMin { 716 for i := lo; i < hi; i++ { 717 nif := nod(OIF, nil, nil) 718 base(i, nif) 719 lineno = lineno.WithNotStmt() 720 nif.Left = typecheck(nif.Left, ctxExpr) 721 nif.Left = defaultlit(nif.Left, nil) 722 out.Append(nif) 723 out = &nif.Rlist 724 } 725 return 726 } 727 728 half := lo + n/2 729 nif := nod(OIF, nil, nil) 730 nif.Left = less(half) 731 lineno = lineno.WithNotStmt() 732 nif.Left = typecheck(nif.Left, ctxExpr) 733 nif.Left = defaultlit(nif.Left, nil) 734 do(lo, half, &nif.Nbody) 735 do(half, hi, &nif.Rlist) 736 out.Append(nif) 737 } 738 739 do(0, n, out) 740 }