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