github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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.Ntype = ntype
    21  	n.Funcdepth = 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.Closure.Closure = v.Outer
    76  		v.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.Closure
    87  		if !n.Captured {
    88  			n.Captured = true
    89  			if n.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.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.Decldepth = 1
   104  		}
   105  	}
   106  
   107  	oldfn := Curfn
   108  	typecheck(&func_.Ntype, Etype)
   109  	func_.Type = func_.Ntype.Type
   110  	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.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.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.Nname = newfuncname(closurename(func_))
   195  	xfunc.Nname.Sym.Flags |= SymExported // disable export
   196  	xfunc.Nname.Ntype = xtype
   197  	xfunc.Nname.Defn = xfunc
   198  	declare(xfunc.Nname, PFUNC)
   199  	xfunc.Nname.Funcdepth = func_.Funcdepth
   200  	xfunc.Funcdepth = func_.Funcdepth
   201  	xfunc.Func.Endlineno = func_.Func.Endlineno
   202  
   203  	xfunc.Nbody = func_.Nbody
   204  	xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl)
   205  	if xfunc.Nbody == nil {
   206  		Fatal("empty body - won't generate any code")
   207  	}
   208  	typecheck(&xfunc, Etop)
   209  
   210  	xfunc.Closure = func_
   211  	func_.Closure = xfunc
   212  
   213  	func_.Nbody = nil
   214  	func_.List = nil
   215  	func_.Rlist = nil
   216  
   217  	return xfunc
   218  }
   219  
   220  // capturevars is called in a separate phase after all typechecking is done.
   221  // It decides whether each variable captured by a closure should be captured
   222  // by value or by reference.
   223  // We use value capturing for values <= 128 bytes that are never reassigned
   224  // after capturing (effectively constant).
   225  func capturevars(xfunc *Node) {
   226  	var v *Node
   227  	var outer *Node
   228  
   229  	lno := int(lineno)
   230  	lineno = xfunc.Lineno
   231  
   232  	func_ := xfunc.Closure
   233  	func_.Func.Enter = nil
   234  	for l := func_.Func.Cvars; l != nil; l = l.Next {
   235  		v = l.N
   236  		if v.Type == nil {
   237  			// if v->type is nil, it means v looked like it was
   238  			// going to be used in the closure but wasn't.
   239  			// this happens because when parsing a, b, c := f()
   240  			// the a, b, c gets parsed as references to older
   241  			// a, b, c before the parser figures out this is a
   242  			// declaration.
   243  			v.Op = OXXX
   244  
   245  			continue
   246  		}
   247  
   248  		// type check the & of closed variables outside the closure,
   249  		// so that the outer frame also grabs them and knows they escape.
   250  		dowidth(v.Type)
   251  
   252  		outer = v.Outerexpr
   253  		v.Outerexpr = nil
   254  
   255  		// out parameters will be assigned to implicitly upon return.
   256  		if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 {
   257  			v.Byval = true
   258  		} else {
   259  			v.Closure.Addrtaken = true
   260  			outer = Nod(OADDR, outer, nil)
   261  		}
   262  
   263  		if Debug['m'] > 1 {
   264  			var name *Sym
   265  			if v.Curfn != nil && v.Curfn.Nname != nil {
   266  				name = v.Curfn.Nname.Sym
   267  			}
   268  			how := "ref"
   269  			if v.Byval {
   270  				how = "value"
   271  			}
   272  			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", Sconv(name, 0), how, Sconv(v.Sym, 0), v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
   273  		}
   274  
   275  		typecheck(&outer, Erv)
   276  		func_.Func.Enter = list(func_.Func.Enter, outer)
   277  	}
   278  
   279  	lineno = int32(lno)
   280  }
   281  
   282  // transformclosure is called in a separate phase after escape analysis.
   283  // It transform closure bodies to properly reference captured variables.
   284  func transformclosure(xfunc *Node) {
   285  	lno := int(lineno)
   286  	lineno = xfunc.Lineno
   287  	func_ := xfunc.Closure
   288  
   289  	if func_.Top&Ecall != 0 {
   290  		// If the closure is directly called, we transform it to a plain function call
   291  		// with variables passed as args. This avoids allocation of a closure object.
   292  		// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
   293  		// will complete the transformation later.
   294  		// For illustration, the following closure:
   295  		//	func(a int) {
   296  		//		println(byval)
   297  		//		byref++
   298  		//	}(42)
   299  		// becomes:
   300  		//	func(a int, byval int, &byref *int) {
   301  		//		println(byval)
   302  		//		(*&byref)++
   303  		//	}(42, byval, &byref)
   304  
   305  		// f is ONAME of the actual function.
   306  		f := xfunc.Nname
   307  
   308  		// Get pointer to input arguments and rewind to the end.
   309  		// We are going to append captured variables to input args.
   310  		param := &getinargx(f.Type).Type
   311  
   312  		for ; *param != nil; param = &(*param).Down {
   313  		}
   314  		var v *Node
   315  		var addr *Node
   316  		var fld *Type
   317  		for l := func_.Func.Cvars; l != nil; l = l.Next {
   318  			v = l.N
   319  			if v.Op == OXXX {
   320  				continue
   321  			}
   322  			fld = typ(TFIELD)
   323  			fld.Funarg = 1
   324  			if v.Byval {
   325  				// If v is captured by value, we merely downgrade it to PPARAM.
   326  				v.Class = PPARAM
   327  
   328  				v.Ullman = 1
   329  				fld.Nname = v
   330  			} else {
   331  				// If v of type T is captured by reference,
   332  				// we introduce function param &v *T
   333  				// and v remains PPARAMREF with &v heapaddr
   334  				// (accesses will implicitly deref &v).
   335  				addr = newname(Lookupf("&%s", v.Sym.Name))
   336  				addr.Type = Ptrto(v.Type)
   337  				addr.Class = PPARAM
   338  				v.Heapaddr = addr
   339  				fld.Nname = addr
   340  			}
   341  
   342  			fld.Type = fld.Nname.Type
   343  			fld.Sym = fld.Nname.Sym
   344  
   345  			// Declare the new param and append it to input arguments.
   346  			xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname)
   347  
   348  			*param = fld
   349  			param = &fld.Down
   350  		}
   351  
   352  		// Recalculate param offsets.
   353  		if f.Type.Width > 0 {
   354  			Fatal("transformclosure: width is already calculated")
   355  		}
   356  		dowidth(f.Type)
   357  		xfunc.Type = f.Type // update type of ODCLFUNC
   358  	} else {
   359  		// The closure is not called, so it is going to stay as closure.
   360  		nvar := 0
   361  
   362  		var body *NodeList
   363  		offset := int64(Widthptr)
   364  		var addr *Node
   365  		var v *Node
   366  		var cv *Node
   367  		for l := func_.Func.Cvars; l != nil; l = l.Next {
   368  			v = l.N
   369  			if v.Op == OXXX {
   370  				continue
   371  			}
   372  			nvar++
   373  
   374  			// cv refers to the field inside of closure OSTRUCTLIT.
   375  			cv = Nod(OCLOSUREVAR, nil, nil)
   376  
   377  			cv.Type = v.Type
   378  			if !v.Byval {
   379  				cv.Type = Ptrto(v.Type)
   380  			}
   381  			offset = Rnd(offset, int64(cv.Type.Align))
   382  			cv.Xoffset = offset
   383  			offset += cv.Type.Width
   384  
   385  			if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
   386  				//  If it is a small variable captured by value, downgrade it to PAUTO.
   387  				// This optimization is currently enabled only for amd64, see:
   388  				// https://github.com/golang/go/issues/9865
   389  				v.Class = PAUTO
   390  
   391  				v.Ullman = 1
   392  				xfunc.Func.Dcl = list(xfunc.Func.Dcl, v)
   393  				body = list(body, Nod(OAS, v, cv))
   394  			} else {
   395  				// Declare variable holding addresses taken from closure
   396  				// and initialize in entry prologue.
   397  				addr = newname(Lookupf("&%s", v.Sym.Name))
   398  				addr.Ntype = Nod(OIND, typenod(v.Type), nil)
   399  				addr.Class = PAUTO
   400  				addr.Used = true
   401  				addr.Curfn = xfunc
   402  				xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
   403  				v.Heapaddr = addr
   404  				if v.Byval {
   405  					cv = Nod(OADDR, cv, nil)
   406  				}
   407  				body = list(body, Nod(OAS, addr, cv))
   408  			}
   409  		}
   410  
   411  		typechecklist(body, Etop)
   412  		walkstmtlist(body)
   413  		xfunc.Func.Enter = body
   414  		xfunc.Func.Needctxt = nvar > 0
   415  	}
   416  
   417  	lineno = int32(lno)
   418  }
   419  
   420  func walkclosure(func_ *Node, init **NodeList) *Node {
   421  	// If no closure vars, don't bother wrapping.
   422  	if func_.Func.Cvars == nil {
   423  		return func_.Closure.Nname
   424  	}
   425  
   426  	// Create closure in the form of a composite literal.
   427  	// supposing the closure captures an int i and a string s
   428  	// and has one float64 argument and no results,
   429  	// the generated code looks like:
   430  	//
   431  	//	clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
   432  	//
   433  	// The use of the struct provides type information to the garbage
   434  	// collector so that it can walk the closure. We could use (in this case)
   435  	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
   436  	// The information appears in the binary in the form of type descriptors;
   437  	// the struct is unnamed so that closures in multiple packages with the
   438  	// same struct type can share the descriptor.
   439  
   440  	typ := Nod(OTSTRUCT, nil, nil)
   441  
   442  	typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
   443  	var typ1 *Node
   444  	var v *Node
   445  	for l := func_.Func.Cvars; l != nil; l = l.Next {
   446  		v = l.N
   447  		if v.Op == OXXX {
   448  			continue
   449  		}
   450  		typ1 = typenod(v.Type)
   451  		if !v.Byval {
   452  			typ1 = Nod(OIND, typ1, nil)
   453  		}
   454  		typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
   455  	}
   456  
   457  	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
   458  	clos.Esc = func_.Esc
   459  	clos.Right.Implicit = true
   460  	clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter)
   461  
   462  	// Force type conversion from *struct to the func type.
   463  	clos = Nod(OCONVNOP, clos, nil)
   464  
   465  	clos.Type = func_.Type
   466  
   467  	typecheck(&clos, Erv)
   468  
   469  	// typecheck will insert a PTRLIT node under CONVNOP,
   470  	// tag it with escape analysis result.
   471  	clos.Left.Esc = func_.Esc
   472  
   473  	// non-escaping temp to use, if any.
   474  	// orderexpr did not compute the type; fill it in now.
   475  	if func_.Alloc != nil {
   476  		func_.Alloc.Type = clos.Left.Left.Type
   477  		func_.Alloc.Orig.Type = func_.Alloc.Type
   478  		clos.Left.Right = func_.Alloc
   479  		func_.Alloc = nil
   480  	}
   481  
   482  	walkexpr(&clos, init)
   483  
   484  	return clos
   485  }
   486  
   487  func typecheckpartialcall(fn *Node, sym *Node) {
   488  	switch fn.Op {
   489  	case ODOTINTER, ODOTMETH:
   490  		break
   491  
   492  	default:
   493  		Fatal("invalid typecheckpartialcall")
   494  	}
   495  
   496  	// Create top-level function.
   497  	fn.Nname = makepartialcall(fn, fn.Type, sym)
   498  
   499  	fn.Right = sym
   500  	fn.Op = OCALLPART
   501  	fn.Type = fn.Nname.Type
   502  }
   503  
   504  var makepartialcall_gopkg *Pkg
   505  
   506  func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
   507  	var p string
   508  
   509  	rcvrtype := fn.Left.Type
   510  	if exportname(meth.Sym.Name) {
   511  		p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name)
   512  	} else {
   513  		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
   514  	}
   515  	basetype := rcvrtype
   516  	if Isptr[rcvrtype.Etype] {
   517  		basetype = basetype.Type
   518  	}
   519  	if basetype.Etype != TINTER && basetype.Sym == nil {
   520  		Fatal("missing base type for %v", Tconv(rcvrtype, 0))
   521  	}
   522  
   523  	var spkg *Pkg
   524  	if basetype.Sym != nil {
   525  		spkg = basetype.Sym.Pkg
   526  	}
   527  	if spkg == nil {
   528  		if makepartialcall_gopkg == nil {
   529  			makepartialcall_gopkg = mkpkg("go")
   530  		}
   531  		spkg = makepartialcall_gopkg
   532  	}
   533  
   534  	sym := Pkglookup(p, spkg)
   535  
   536  	if sym.Flags&SymUniq != 0 {
   537  		return sym.Def
   538  	}
   539  	sym.Flags |= SymUniq
   540  
   541  	savecurfn := Curfn
   542  	Curfn = nil
   543  
   544  	xtype := Nod(OTFUNC, nil, nil)
   545  	i := 0
   546  	var l *NodeList
   547  	var callargs *NodeList
   548  	ddd := false
   549  	xfunc := Nod(ODCLFUNC, nil, nil)
   550  	Curfn = xfunc
   551  	var fld *Node
   552  	var n *Node
   553  	for t := getinargx(t0).Type; t != nil; t = t.Down {
   554  		n = newname(Lookupf("a%d", i))
   555  		i++
   556  		n.Class = PPARAM
   557  		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
   558  		callargs = list(callargs, n)
   559  		fld = Nod(ODCLFIELD, n, typenod(t.Type))
   560  		if t.Isddd {
   561  			fld.Isddd = true
   562  			ddd = true
   563  		}
   564  
   565  		l = list(l, fld)
   566  	}
   567  
   568  	xtype.List = l
   569  	i = 0
   570  	l = nil
   571  	var retargs *NodeList
   572  	for t := getoutargx(t0).Type; t != nil; t = t.Down {
   573  		n = newname(Lookupf("r%d", i))
   574  		i++
   575  		n.Class = PPARAMOUT
   576  		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
   577  		retargs = list(retargs, n)
   578  		l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
   579  	}
   580  
   581  	xtype.Rlist = l
   582  
   583  	xfunc.Func.Dupok = true
   584  	xfunc.Nname = newfuncname(sym)
   585  	xfunc.Nname.Sym.Flags |= SymExported // disable export
   586  	xfunc.Nname.Ntype = xtype
   587  	xfunc.Nname.Defn = xfunc
   588  	declare(xfunc.Nname, PFUNC)
   589  
   590  	// Declare and initialize variable holding receiver.
   591  
   592  	xfunc.Func.Needctxt = true
   593  	cv := Nod(OCLOSUREVAR, nil, nil)
   594  	cv.Xoffset = int64(Widthptr)
   595  	cv.Type = rcvrtype
   596  	if int(cv.Type.Align) > Widthptr {
   597  		cv.Xoffset = int64(cv.Type.Align)
   598  	}
   599  	ptr := Nod(ONAME, nil, nil)
   600  	ptr.Sym = Lookup("rcvr")
   601  	ptr.Class = PAUTO
   602  	ptr.Addable = true
   603  	ptr.Ullman = 1
   604  	ptr.Used = true
   605  	ptr.Curfn = xfunc
   606  	xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
   607  	var body *NodeList
   608  	if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
   609  		ptr.Ntype = typenod(rcvrtype)
   610  		body = list(body, Nod(OAS, ptr, cv))
   611  	} else {
   612  		ptr.Ntype = typenod(Ptrto(rcvrtype))
   613  		body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
   614  	}
   615  
   616  	call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
   617  	call.List = callargs
   618  	call.Isddd = ddd
   619  	if t0.Outtuple == 0 {
   620  		body = list(body, call)
   621  	} else {
   622  		n := Nod(OAS2, nil, nil)
   623  		n.List = retargs
   624  		n.Rlist = list1(call)
   625  		body = list(body, n)
   626  		n = Nod(ORETURN, nil, nil)
   627  		body = list(body, n)
   628  	}
   629  
   630  	xfunc.Nbody = body
   631  
   632  	typecheck(&xfunc, Etop)
   633  	sym.Def = xfunc
   634  	xtop = list(xtop, xfunc)
   635  	Curfn = savecurfn
   636  
   637  	return xfunc
   638  }
   639  
   640  func walkpartialcall(n *Node, init **NodeList) *Node {
   641  	// Create closure in the form of a composite literal.
   642  	// For x.M with receiver (x) type T, the generated code looks like:
   643  	//
   644  	//	clos = &struct{F uintptr; R T}{M.T·f, x}
   645  	//
   646  	// Like walkclosure above.
   647  
   648  	if Isinter(n.Left.Type) {
   649  		// Trigger panic for method on nil interface now.
   650  		// Otherwise it happens in the wrapper and is confusing.
   651  		n.Left = cheapexpr(n.Left, init)
   652  
   653  		checknil(n.Left, init)
   654  	}
   655  
   656  	typ := Nod(OTSTRUCT, nil, nil)
   657  	typ.List = list1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
   658  	typ.List = list(typ.List, Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
   659  
   660  	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
   661  	clos.Esc = n.Esc
   662  	clos.Right.Implicit = true
   663  	clos.List = list1(Nod(OCFUNC, n.Nname.Nname, nil))
   664  	clos.List = list(clos.List, n.Left)
   665  
   666  	// Force type conversion from *struct to the func type.
   667  	clos = Nod(OCONVNOP, clos, nil)
   668  
   669  	clos.Type = n.Type
   670  
   671  	typecheck(&clos, Erv)
   672  
   673  	// typecheck will insert a PTRLIT node under CONVNOP,
   674  	// tag it with escape analysis result.
   675  	clos.Left.Esc = n.Esc
   676  
   677  	// non-escaping temp to use, if any.
   678  	// orderexpr did not compute the type; fill it in now.
   679  	if n.Alloc != nil {
   680  		n.Alloc.Type = clos.Left.Left.Type
   681  		n.Alloc.Orig.Type = n.Alloc.Type
   682  		clos.Left.Right = n.Alloc
   683  		n.Alloc = nil
   684  	}
   685  
   686  	walkexpr(&clos, init)
   687  
   688  	return clos
   689  }