github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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/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.T·f, 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  }