github.com/yukk001/go1.10.8@v0.0.0-20190813125351-6df2d3982e20/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 fields := []*Node{ 484 namedfield(".F", types.Types[TUINTPTR]), 485 } 486 for _, v := range func_.Func.Cvars.Slice() { 487 if v.Op == OXXX { 488 continue 489 } 490 typ := v.Type 491 if !v.Name.Byval() { 492 typ = types.NewPtr(typ) 493 } 494 fields = append(fields, symfield(v.Sym, typ)) 495 } 496 typ := tostruct(fields) 497 typ.SetNoalg(true) 498 499 clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil)) 500 clos.Esc = func_.Esc 501 clos.Right.SetImplicit(true) 502 clos.List.Set(append([]*Node{nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...)) 503 504 // Force type conversion from *struct to the func type. 505 clos = nod(OCONVNOP, clos, nil) 506 clos.Type = func_.Type 507 508 clos = typecheck(clos, Erv) 509 510 // typecheck will insert a PTRLIT node under CONVNOP, 511 // tag it with escape analysis result. 512 clos.Left.Esc = func_.Esc 513 514 // non-escaping temp to use, if any. 515 // orderexpr did not compute the type; fill it in now. 516 if x := prealloc[func_]; x != nil { 517 x.Type = clos.Left.Left.Type 518 x.Orig.Type = x.Type 519 clos.Left.Right = x 520 delete(prealloc, func_) 521 } 522 523 return walkexpr(clos, init) 524 } 525 526 func typecheckpartialcall(fn *Node, sym *types.Sym) { 527 switch fn.Op { 528 case ODOTINTER, ODOTMETH: 529 break 530 531 default: 532 Fatalf("invalid typecheckpartialcall") 533 } 534 535 // Create top-level function. 536 xfunc := makepartialcall(fn, fn.Type, sym) 537 fn.Func = xfunc.Func 538 fn.Right = newname(sym) 539 fn.Op = OCALLPART 540 fn.Type = xfunc.Type 541 } 542 543 var makepartialcall_gopkg *types.Pkg 544 545 func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node { 546 var p string 547 548 rcvrtype := fn.Left.Type 549 if exportname(meth.Name) { 550 p = fmt.Sprintf("(%-S).%s-fm", rcvrtype, meth.Name) 551 } else { 552 p = fmt.Sprintf("(%-S).(%-v)-fm", rcvrtype, meth) 553 } 554 basetype := rcvrtype 555 if rcvrtype.IsPtr() { 556 basetype = basetype.Elem() 557 } 558 if !basetype.IsInterface() && basetype.Sym == nil { 559 Fatalf("missing base type for %v", rcvrtype) 560 } 561 562 var spkg *types.Pkg 563 if basetype.Sym != nil { 564 spkg = basetype.Sym.Pkg 565 } 566 if spkg == nil { 567 if makepartialcall_gopkg == nil { 568 makepartialcall_gopkg = types.NewPkg("go", "") 569 } 570 spkg = makepartialcall_gopkg 571 } 572 573 sym := spkg.Lookup(p) 574 575 if sym.Uniq() { 576 return asNode(sym.Def) 577 } 578 sym.SetUniq(true) 579 580 savecurfn := Curfn 581 Curfn = nil 582 583 xtype := nod(OTFUNC, nil, nil) 584 var l []*Node 585 var callargs []*Node 586 ddd := false 587 xfunc := nod(ODCLFUNC, nil, nil) 588 Curfn = xfunc 589 for i, t := range t0.Params().Fields().Slice() { 590 n := newname(lookupN("a", i)) 591 n.SetClass(PPARAM) 592 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n) 593 callargs = append(callargs, n) 594 fld := nod(ODCLFIELD, n, typenod(t.Type)) 595 if t.Isddd() { 596 fld.SetIsddd(true) 597 ddd = true 598 } 599 600 l = append(l, fld) 601 } 602 603 xtype.List.Set(l) 604 l = nil 605 var retargs []*Node 606 for i, t := range t0.Results().Fields().Slice() { 607 n := newname(lookupN("r", i)) 608 n.SetClass(PPARAMOUT) 609 xfunc.Func.Dcl = append(xfunc.Func.Dcl, n) 610 retargs = append(retargs, n) 611 l = append(l, nod(ODCLFIELD, n, typenod(t.Type))) 612 } 613 614 xtype.Rlist.Set(l) 615 616 xfunc.Func.SetDupok(true) 617 xfunc.Func.Nname = newfuncname(sym) 618 xfunc.Func.Nname.Sym.SetExported(true) // disable export 619 xfunc.Func.Nname.Name.Param.Ntype = xtype 620 xfunc.Func.Nname.Name.Defn = xfunc 621 declare(xfunc.Func.Nname, PFUNC) 622 623 // Declare and initialize variable holding receiver. 624 625 xfunc.Func.SetNeedctxt(true) 626 cv := nod(OCLOSUREVAR, nil, nil) 627 cv.Xoffset = int64(Widthptr) 628 cv.Type = rcvrtype 629 if int(cv.Type.Align) > Widthptr { 630 cv.Xoffset = int64(cv.Type.Align) 631 } 632 ptr := newname(lookup("rcvr")) 633 ptr.SetClass(PAUTO) 634 ptr.Name.SetUsed(true) 635 ptr.Name.Curfn = xfunc 636 xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr) 637 var body []*Node 638 if rcvrtype.IsPtr() || rcvrtype.IsInterface() { 639 ptr.Type = rcvrtype 640 body = append(body, nod(OAS, ptr, cv)) 641 } else { 642 ptr.Type = types.NewPtr(rcvrtype) 643 body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil))) 644 } 645 646 call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil) 647 call.List.Set(callargs) 648 call.SetIsddd(ddd) 649 if t0.NumResults() == 0 { 650 body = append(body, call) 651 } else { 652 n := nod(OAS2, nil, nil) 653 n.List.Set(retargs) 654 n.Rlist.Set1(call) 655 body = append(body, n) 656 n = nod(ORETURN, nil, nil) 657 body = append(body, n) 658 } 659 660 xfunc.Nbody.Set(body) 661 662 xfunc = typecheck(xfunc, Etop) 663 sym.Def = asTypesNode(xfunc) 664 xtop = append(xtop, xfunc) 665 Curfn = savecurfn 666 667 return xfunc 668 } 669 670 func walkpartialcall(n *Node, init *Nodes) *Node { 671 // Create closure in the form of a composite literal. 672 // For x.M with receiver (x) type T, the generated code looks like: 673 // 674 // clos = &struct{F uintptr; R T}{M.T·f, x} 675 // 676 // Like walkclosure above. 677 678 if n.Left.Type.IsInterface() { 679 // Trigger panic for method on nil interface now. 680 // Otherwise it happens in the wrapper and is confusing. 681 n.Left = cheapexpr(n.Left, init) 682 683 checknil(n.Left, init) 684 } 685 686 typ := tostruct([]*Node{ 687 namedfield("F", types.Types[TUINTPTR]), 688 namedfield("R", n.Left.Type), 689 }) 690 typ.SetNoalg(true) 691 692 clos := nod(OCOMPLIT, nil, nod(OIND, typenod(typ), nil)) 693 clos.Esc = n.Esc 694 clos.Right.SetImplicit(true) 695 clos.List.Set1(nod(OCFUNC, n.Func.Nname, nil)) 696 clos.List.Append(n.Left) 697 698 // Force type conversion from *struct to the func type. 699 clos = nod(OCONVNOP, clos, nil) 700 clos.Type = n.Type 701 702 clos = typecheck(clos, Erv) 703 704 // typecheck will insert a PTRLIT node under CONVNOP, 705 // tag it with escape analysis result. 706 clos.Left.Esc = n.Esc 707 708 // non-escaping temp to use, if any. 709 // orderexpr did not compute the type; fill it in now. 710 if x := prealloc[n]; x != nil { 711 x.Type = clos.Left.Left.Type 712 x.Orig.Type = x.Type 713 clos.Left.Right = x 714 delete(prealloc, n) 715 } 716 717 return walkexpr(clos, init) 718 }