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