github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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/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.T·f, 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  }