github.com/Filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/cmd/compile/internal/gc/closure.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/syntax" 9 "cmd/compile/internal/types" 10 "fmt" 11 ) 12 13 func (p *noder) funcLit(expr *syntax.FuncLit) *Node { 14 ntype := p.typeExpr(expr.Type) 15 16 n := p.nod(expr, OCLOSURE, nil, nil) 17 n.Func.SetIsHiddenClosure(Curfn != nil) 18 n.Func.Ntype = ntype 19 n.Func.Depth = funcdepth 20 n.Func.Outerfunc = Curfn 21 22 old := p.funchdr(n) 23 24 // steal ntype's argument names and 25 // leave a fresh copy in their place. 26 // references to these variables need to 27 // refer to the variables in the external 28 // function declared below; see walkclosure. 29 n.List.Set(ntype.List.Slice()) 30 n.Rlist.Set(ntype.Rlist.Slice()) 31 32 ntype.List.Set(nil) 33 ntype.Rlist.Set(nil) 34 for _, n1 := range n.List.Slice() { 35 name := n1.Left 36 if name != nil { 37 name = newname(name.Sym) 38 } 39 a := nod(ODCLFIELD, name, n1.Right) 40 a.SetIsddd(n1.Isddd()) 41 if name != nil { 42 name.SetIsddd(a.Isddd()) 43 } 44 ntype.List.Append(a) 45 } 46 for _, n2 := range n.Rlist.Slice() { 47 name := n2.Left 48 if name != nil { 49 name = newname(name.Sym) 50 } 51 ntype.Rlist.Append(nod(ODCLFIELD, name, n2.Right)) 52 } 53 54 body := p.stmts(expr.Body.List) 55 56 lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace) 57 if len(body) == 0 { 58 body = []*Node{nod(OEMPTY, nil, nil)} 59 } 60 61 n.Nbody.Set(body) 62 n.Func.Endlineno = lineno 63 p.funcbody(old) 64 65 // closure-specific variables are hanging off the 66 // ordinary ones in the symbol table; see oldname. 67 // unhook them. 68 // make the list of pointers for the closure call. 69 for _, v := range n.Func.Cvars.Slice() { 70 // Unlink from v1; see comment in syntax.go type Param for these fields. 71 v1 := v.Name.Defn 72 v1.Name.Param.Innermost = v.Name.Param.Outer 73 74 // If the closure usage of v is not dense, 75 // we need to make it dense; now that we're out 76 // of the function in which v appeared, 77 // look up v.Sym in the enclosing function 78 // and keep it around for use in the compiled code. 79 // 80 // That is, suppose we just finished parsing the innermost 81 // closure f4 in this code: 82 // 83 // func f() { 84 // v := 1 85 // func() { // f2 86 // use(v) 87 // func() { // f3 88 // func() { // f4 89 // use(v) 90 // }() 91 // }() 92 // }() 93 // } 94 // 95 // At this point v.Outer is f2's v; there is no f3's v. 96 // To construct the closure f4 from within f3, 97 // we need to use f3's v and in this case we need to create f3's v. 98 // We are now in the context of f3, so calling oldname(v.Sym) 99 // obtains f3's v, creating it if necessary (as it is in the example). 100 // 101 // capturevars will decide whether to use v directly or &v. 102 v.Name.Param.Outer = oldname(v.Sym) 103 } 104 105 return n 106 } 107 108 func typecheckclosure(func_ *Node, top int) { 109 for _, ln := range func_.Func.Cvars.Slice() { 110 n := ln.Name.Defn 111 if !n.Name.Captured() { 112 n.Name.SetCaptured(true) 113 if n.Name.Decldepth == 0 { 114 Fatalf("typecheckclosure: var %S does not have decldepth assigned", n) 115 } 116 117 // Ignore assignments to the variable in straightline code 118 // preceding the first capturing by a closure. 119 if n.Name.Decldepth == decldepth { 120 n.SetAssigned(false) 121 } 122 } 123 } 124 125 for _, ln := range func_.Func.Dcl { 126 if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) { 127 ln.Name.Decldepth = 1 128 } 129 } 130 131 oldfn := Curfn 132 func_.Func.Ntype = typecheck(func_.Func.Ntype, Etype) 133 func_.Type = func_.Func.Ntype.Type 134 func_.Func.Top = top 135 136 // Type check the body now, but only if we're inside a function. 137 // At top level (in a variable initialization: curfn==nil) we're not 138 // ready to type check code yet; we'll check it later, because the 139 // underlying closure function we create is added to xtop. 140 if Curfn != nil && func_.Type != nil { 141 Curfn = func_ 142 olddd := decldepth 143 decldepth = 1 144 typecheckslice(func_.Nbody.Slice(), Etop) 145 decldepth = olddd 146 Curfn = oldfn 147 } 148 149 // Create top-level function 150 xtop = append(xtop, makeclosure(func_)) 151 } 152 153 // closurename returns name for OCLOSURE n. 154 // It is not as simple as it ought to be, because we typecheck nested closures 155 // starting from the innermost one. So when we check the inner closure, 156 // we don't yet have name for the outer closure. This function uses recursion 157 // to generate names all the way up if necessary. 158 159 var closurename_closgen int 160 161 func closurename(n *Node) *types.Sym { 162 if n.Sym != nil { 163 return n.Sym 164 } 165 gen := 0 166 outer := "" 167 prefix := "" 168 switch { 169 case n.Func.Outerfunc == nil: 170 // Global closure. 171 outer = "glob." 172 173 prefix = "func" 174 closurename_closgen++ 175 gen = closurename_closgen 176 case n.Func.Outerfunc.Op == ODCLFUNC: 177 // The outermost closure inside of a named function. 178 outer = n.Func.Outerfunc.funcname() 179 180 prefix = "func" 181 182 // Yes, functions can be named _. 183 // Can't use function closgen in such case, 184 // because it would lead to name clashes. 185 if !isblank(n.Func.Outerfunc.Func.Nname) { 186 n.Func.Outerfunc.Func.Closgen++ 187 gen = n.Func.Outerfunc.Func.Closgen 188 } else { 189 closurename_closgen++ 190 gen = closurename_closgen 191 } 192 case n.Func.Outerfunc.Op == OCLOSURE: 193 // Nested closure, recurse. 194 outer = closurename(n.Func.Outerfunc).Name 195 196 prefix = "" 197 n.Func.Outerfunc.Func.Closgen++ 198 gen = n.Func.Outerfunc.Func.Closgen 199 default: 200 Fatalf("closurename called for %S", n) 201 } 202 n.Sym = lookup(fmt.Sprintf("%s.%s%d", outer, prefix, gen)) 203 return n.Sym 204 } 205 206 func makeclosure(func_ *Node) *Node { 207 // wrap body in external function 208 // that begins by reading closure parameters. 209 xtype := nod(OTFUNC, nil, nil) 210 211 xtype.List.Set(func_.List.Slice()) 212 xtype.Rlist.Set(func_.Rlist.Slice()) 213 214 // create the function 215 xfunc := nod(ODCLFUNC, nil, nil) 216 xfunc.Func.SetIsHiddenClosure(Curfn != nil) 217 218 xfunc.Func.Nname = newfuncname(closurename(func_)) 219 xfunc.Func.Nname.Sym.SetExported(true) // disable export 220 xfunc.Func.Nname.Name.Param.Ntype = xtype 221 xfunc.Func.Nname.Name.Defn = xfunc 222 declare(xfunc.Func.Nname, PFUNC) 223 xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth 224 xfunc.Func.Depth = func_.Func.Depth 225 xfunc.Func.Endlineno = func_.Func.Endlineno 226 if Ctxt.Flag_dynlink { 227 makefuncsym(xfunc.Func.Nname.Sym) 228 } 229 230 xfunc.Nbody.Set(func_.Nbody.Slice()) 231 xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...) 232 xfunc.Func.Parents = func_.Func.Parents 233 xfunc.Func.Marks = func_.Func.Marks 234 func_.Func.Dcl = nil 235 func_.Func.Parents = nil 236 func_.Func.Marks = nil 237 if xfunc.Nbody.Len() == 0 { 238 Fatalf("empty body - won't generate any code") 239 } 240 xfunc = typecheck(xfunc, Etop) 241 242 xfunc.Func.Closure = func_ 243 func_.Func.Closure = xfunc 244 245 func_.Nbody.Set(nil) 246 func_.List.Set(nil) 247 func_.Rlist.Set(nil) 248 249 return xfunc 250 } 251 252 // capturevarscomplete is set to true when the capturevars phase is done. 253 var capturevarscomplete bool 254 255 // capturevars is called in a separate phase after all typechecking is done. 256 // It decides whether each variable captured by a closure should be captured 257 // by value or by reference. 258 // We use value capturing for values <= 128 bytes that are never reassigned 259 // after capturing (effectively constant). 260 func capturevars(xfunc *Node) { 261 lno := lineno 262 lineno = xfunc.Pos 263 264 func_ := xfunc.Func.Closure 265 func_.Func.Enter.Set(nil) 266 for _, v := range func_.Func.Cvars.Slice() { 267 if v.Type == nil { 268 // if v->type is nil, it means v looked like it was 269 // going to be used in the closure but wasn't. 270 // this happens because when parsing a, b, c := f() 271 // the a, b, c gets parsed as references to older 272 // a, b, c before the parser figures out this is a 273 // declaration. 274 v.Op = OXXX 275 276 continue 277 } 278 279 // type check the & of closed variables outside the closure, 280 // so that the outer frame also grabs them and knows they escape. 281 dowidth(v.Type) 282 283 outer := v.Name.Param.Outer 284 outermost := v.Name.Defn 285 286 // out parameters will be assigned to implicitly upon return. 287 if outer.Class() != PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && v.Type.Width <= 128 { 288 v.Name.SetByval(true) 289 } else { 290 outermost.SetAddrtaken(true) 291 outer = nod(OADDR, outer, nil) 292 } 293 294 if Debug['m'] > 1 { 295 var name *types.Sym 296 if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil { 297 name = v.Name.Curfn.Func.Nname.Sym 298 } 299 how := "ref" 300 if v.Name.Byval() { 301 how = "value" 302 } 303 Warnl(v.Pos, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken(), outermost.Assigned(), int32(v.Type.Width)) 304 } 305 306 outer = typecheck(outer, Erv) 307 func_.Func.Enter.Append(outer) 308 } 309 310 lineno = lno 311 } 312 313 // transformclosure is called in a separate phase after escape analysis. 314 // It transform closure bodies to properly reference captured variables. 315 func transformclosure(xfunc *Node) { 316 lno := lineno 317 lineno = xfunc.Pos 318 func_ := xfunc.Func.Closure 319 320 if func_.Func.Top&Ecall != 0 { 321 // If the closure is directly called, we transform it to a plain function call 322 // with variables passed as args. This avoids allocation of a closure object. 323 // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE) 324 // will complete the transformation later. 325 // For illustration, the following closure: 326 // func(a int) { 327 // println(byval) 328 // byref++ 329 // }(42) 330 // becomes: 331 // func(byval int, &byref *int, a int) { 332 // println(byval) 333 // (*&byref)++ 334 // }(byval, &byref, 42) 335 336 // f is ONAME of the actual function. 337 f := xfunc.Func.Nname 338 339 // We are going to insert captured variables before input args. 340 var params []*types.Field 341 var decls []*Node 342 for _, v := range func_.Func.Cvars.Slice() { 343 if v.Op == OXXX { 344 continue 345 } 346 fld := types.NewField() 347 fld.Funarg = types.FunargParams 348 if v.Name.Byval() { 349 // If v is captured by value, we merely downgrade it to PPARAM. 350 v.SetClass(PPARAM) 351 fld.Nname = asTypesNode(v) 352 } else { 353 // If v of type T is captured by reference, 354 // we introduce function param &v *T 355 // and v remains PAUTOHEAP with &v heapaddr 356 // (accesses will implicitly deref &v). 357 addr := newname(lookup("&" + v.Sym.Name)) 358 addr.Type = types.NewPtr(v.Type) 359 addr.SetClass(PPARAM) 360 v.Name.Param.Heapaddr = addr 361 fld.Nname = asTypesNode(addr) 362 } 363 364 fld.Type = asNode(fld.Nname).Type 365 fld.Sym = asNode(fld.Nname).Sym 366 367 params = append(params, fld) 368 decls = append(decls, asNode(fld.Nname)) 369 } 370 371 if len(params) > 0 { 372 // Prepend params and decls. 373 f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...)) 374 xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...) 375 } 376 377 dowidth(f.Type) 378 xfunc.Type = f.Type // update type of ODCLFUNC 379 } else { 380 // The closure is not called, so it is going to stay as closure. 381 var body []*Node 382 offset := int64(Widthptr) 383 for _, v := range func_.Func.Cvars.Slice() { 384 if v.Op == OXXX { 385 continue 386 } 387 388 // cv refers to the field inside of closure OSTRUCTLIT. 389 cv := nod(OCLOSUREVAR, nil, nil) 390 391 cv.Type = v.Type 392 if !v.Name.Byval() { 393 cv.Type = types.NewPtr(v.Type) 394 } 395 offset = Rnd(offset, int64(cv.Type.Align)) 396 cv.Xoffset = offset 397 offset += cv.Type.Width 398 399 if v.Name.Byval() && v.Type.Width <= int64(2*Widthptr) { 400 // If it is a small variable captured by value, downgrade it to PAUTO. 401 v.SetClass(PAUTO) 402 xfunc.Func.Dcl = append(xfunc.Func.Dcl, v) 403 body = append(body, nod(OAS, v, cv)) 404 } else { 405 // Declare variable holding addresses taken from closure 406 // and initialize in entry prologue. 407 addr := newname(lookup("&" + v.Sym.Name)) 408 addr.Type = types.NewPtr(v.Type) 409 addr.SetClass(PAUTO) 410 addr.Name.SetUsed(true) 411 addr.Name.Curfn = xfunc 412 xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr) 413 v.Name.Param.Heapaddr = addr 414 if v.Name.Byval() { 415 cv = nod(OADDR, cv, nil) 416 } 417 body = append(body, nod(OAS, addr, cv)) 418 } 419 } 420 421 if len(body) > 0 { 422 typecheckslice(body, Etop) 423 walkstmtlist(body) 424 xfunc.Func.Enter.Set(body) 425 xfunc.Func.SetNeedctxt(true) 426 } 427 } 428 429 lineno = lno 430 } 431 432 // hasemptycvars returns true iff closure func_ has an 433 // empty list of captured vars. OXXX nodes don't count. 434 func hasemptycvars(func_ *Node) bool { 435 for _, v := range func_.Func.Cvars.Slice() { 436 if v.Op == OXXX { 437 continue 438 } 439 return false 440 } 441 return true 442 } 443 444 // closuredebugruntimecheck applies boilerplate checks for debug flags 445 // and compiling runtime 446 func closuredebugruntimecheck(r *Node) { 447 if Debug_closure > 0 { 448 if r.Esc == EscHeap { 449 Warnl(r.Pos, "heap closure, captured vars = %v", r.Func.Cvars) 450 } else { 451 Warnl(r.Pos, "stack closure, captured vars = %v", r.Func.Cvars) 452 } 453 } 454 if compiling_runtime && r.Esc == EscHeap { 455 yyerrorl(r.Pos, "heap-allocated closure, not allowed in runtime.") 456 } 457 } 458 459 func walkclosure(func_ *Node, init *Nodes) *Node { 460 // If no closure vars, don't bother wrapping. 461 if hasemptycvars(func_) { 462 if Debug_closure > 0 { 463 Warnl(func_.Pos, "closure converted to global") 464 } 465 return func_.Func.Closure.Func.Nname 466 } 467 closuredebugruntimecheck(func_) 468 469 // Create closure in the form of a composite literal. 470 // supposing the closure captures an int i and a string s 471 // and has one float64 argument and no results, 472 // the generated code looks like: 473 // 474 // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s} 475 // 476 // The use of the struct provides type information to the garbage 477 // collector so that it can walk the closure. We could use (in this case) 478 // [3]unsafe.Pointer instead, but that would leave the gc in the dark. 479 // The information appears in the binary in the form of type descriptors; 480 // the struct is unnamed so that closures in multiple packages with the 481 // same struct type can share the descriptor. 482 483 typ := nod(OTSTRUCT, nil, nil) 484 485 typ.List.Set1(namedfield(".F", types.Types[TUINTPTR])) 486 for _, v := range func_.Func.Cvars.Slice() { 487 if v.Op == OXXX { 488 continue 489 } 490 typ1 := typenod(v.Type) 491 if !v.Name.Byval() { 492 typ1 = nod(OIND, typ1, nil) 493 } 494 typ.List.Append(nod(ODCLFIELD, newname(v.Sym), typ1)) 495 } 496 497 clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil)) 498 clos.Esc = func_.Esc 499 clos.Right.SetImplicit(true) 500 clos.List.Set(append([]*Node{nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...)) 501 502 // Force type conversion from *struct to the func type. 503 clos = nod(OCONVNOP, clos, nil) 504 505 clos.Type = func_.Type 506 507 clos = typecheck(clos, Erv) 508 509 // typecheck will insert a PTRLIT node under CONVNOP, 510 // tag it with escape analysis result. 511 clos.Left.Esc = func_.Esc 512 513 // non-escaping temp to use, if any. 514 // orderexpr did not compute the type; fill it in now. 515 if x := prealloc[func_]; x != nil { 516 x.Type = clos.Left.Left.Type 517 x.Orig.Type = x.Type 518 clos.Left.Right = x 519 delete(prealloc, func_) 520 } 521 522 return walkexpr(clos, init) 523 } 524 525 func typecheckpartialcall(fn *Node, sym *types.Sym) { 526 switch fn.Op { 527 case ODOTINTER, ODOTMETH: 528 break 529 530 default: 531 Fatalf("invalid typecheckpartialcall") 532 } 533 534 // Create top-level function. 535 xfunc := makepartialcall(fn, fn.Type, sym) 536 fn.Func = xfunc.Func 537 fn.Right = newname(sym) 538 fn.Op = OCALLPART 539 fn.Type = xfunc.Type 540 } 541 542 var makepartialcall_gopkg *types.Pkg 543 544 func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { 545 var p string 546 547 rcvrtype := fn.Left.Type 548 if exportname(meth.Name) { 549 p = fmt.Sprintf("(%-S).%s-fm", rcvrtype, meth.Name) 550 } else { 551 p = fmt.Sprintf("(%-S).(%-v)-fm", rcvrtype, meth) 552 } 553 basetype := rcvrtype 554 if rcvrtype.IsPtr() { 555 basetype = basetype.Elem() 556 } 557 if !basetype.IsInterface() && basetype.Sym == nil { 558 Fatalf("missing base type for %v", rcvrtype) 559 } 560 561 var spkg *types.Pkg 562 if basetype.Sym != nil { 563 spkg = basetype.Sym.Pkg 564 } 565 if spkg == nil { 566 if makepartialcall_gopkg == nil { 567 makepartialcall_gopkg = types.NewPkg("go", "") 568 } 569 spkg = makepartialcall_gopkg 570 } 571 572 sym := spkg.Lookup(p) 573 574 if sym.Uniq() { 575 return asNode(sym.Def) 576 } 577 sym.SetUniq(true) 578 579 savecurfn := Curfn 580 Curfn = nil 581 582 xtype := nod(OTFUNC, nil, nil) 583 var l []*Node 584 var callargs []*Node 585 ddd := false 586 xfunc := nod(ODCLFUNC, nil, nil) 587 Curfn = xfunc 588 for i, t := range t0.Params().Fields().Slice() { 589 n := newname(lookupN("a", i)) 590 n.SetClass(PPARAM) 591 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n) 592 callargs = append(callargs, n) 593 fld := nod(ODCLFIELD, n, typenod(t.Type)) 594 if t.Isddd() { 595 fld.SetIsddd(true) 596 ddd = true 597 } 598 599 l = append(l, fld) 600 } 601 602 xtype.List.Set(l) 603 l = nil 604 var retargs []*Node 605 for i, t := range t0.Results().Fields().Slice() { 606 n := newname(lookupN("r", i)) 607 n.SetClass(PPARAMOUT) 608 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n) 609 retargs = append(retargs, n) 610 l = append(l, nod(ODCLFIELD, n, typenod(t.Type))) 611 } 612 613 xtype.Rlist.Set(l) 614 615 xfunc.Func.SetDupok(true) 616 xfunc.Func.Nname = newfuncname(sym) 617 xfunc.Func.Nname.Sym.SetExported(true) // disable export 618 xfunc.Func.Nname.Name.Param.Ntype = xtype 619 xfunc.Func.Nname.Name.Defn = xfunc 620 declare(xfunc.Func.Nname, PFUNC) 621 622 // Declare and initialize variable holding receiver. 623 624 xfunc.Func.SetNeedctxt(true) 625 cv := nod(OCLOSUREVAR, nil, nil) 626 cv.Xoffset = int64(Widthptr) 627 cv.Type = rcvrtype 628 if int(cv.Type.Align) > Widthptr { 629 cv.Xoffset = int64(cv.Type.Align) 630 } 631 ptr := newname(lookup("rcvr")) 632 ptr.SetClass(PAUTO) 633 ptr.Name.SetUsed(true) 634 ptr.Name.Curfn = xfunc 635 xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr) 636 var body []*Node 637 if rcvrtype.IsPtr() || rcvrtype.IsInterface() { 638 ptr.Type = rcvrtype 639 body = append(body, nod(OAS, ptr, cv)) 640 } else { 641 ptr.Type = types.NewPtr(rcvrtype) 642 body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil))) 643 } 644 645 call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil) 646 call.List.Set(callargs) 647 call.SetIsddd(ddd) 648 if t0.NumResults() == 0 { 649 body = append(body, call) 650 } else { 651 n := nod(OAS2, nil, nil) 652 n.List.Set(retargs) 653 n.Rlist.Set1(call) 654 body = append(body, n) 655 n = nod(ORETURN, nil, nil) 656 body = append(body, n) 657 } 658 659 xfunc.Nbody.Set(body) 660 661 xfunc = typecheck(xfunc, Etop) 662 sym.Def = asTypesNode(xfunc) 663 xtop = append(xtop, xfunc) 664 Curfn = savecurfn 665 666 return xfunc 667 } 668 669 func walkpartialcall(n *Node, init *Nodes) *Node { 670 // Create closure in the form of a composite literal. 671 // For x.M with receiver (x) type T, the generated code looks like: 672 // 673 // clos = &struct{F uintptr; R T}{M.T·f, x} 674 // 675 // Like walkclosure above. 676 677 if n.Left.Type.IsInterface() { 678 // Trigger panic for method on nil interface now. 679 // Otherwise it happens in the wrapper and is confusing. 680 n.Left = cheapexpr(n.Left, init) 681 682 checknil(n.Left, init) 683 } 684 685 typ := nod(OTSTRUCT, nil, nil) 686 typ.List.Set1(namedfield("F", types.Types[TUINTPTR])) 687 typ.List.Append(namedfield("R", n.Left.Type)) 688 689 clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil)) 690 clos.Esc = n.Esc 691 clos.Right.SetImplicit(true) 692 clos.List.Set1(nod(OCFUNC, n.Func.Nname, nil)) 693 clos.List.Append(n.Left) 694 695 // Force type conversion from *struct to the func type. 696 clos = nod(OCONVNOP, clos, nil) 697 698 clos.Type = n.Type 699 700 clos = typecheck(clos, Erv) 701 702 // typecheck will insert a PTRLIT node under CONVNOP, 703 // tag it with escape analysis result. 704 clos.Left.Esc = n.Esc 705 706 // non-escaping temp to use, if any. 707 // orderexpr did not compute the type; fill it in now. 708 if x := prealloc[n]; x != nil { 709 x.Type = clos.Left.Left.Type 710 x.Orig.Type = x.Type 711 clos.Left.Right = x 712 delete(prealloc, n) 713 } 714 715 return walkexpr(clos, init) 716 }