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