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/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.Tf, 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 }
    719