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