1// Copyright 2020 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
5package ir
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/compile/internal/types"
10	"cmd/internal/obj"
11	"cmd/internal/objabi"
12	"cmd/internal/src"
13	"fmt"
14	"strings"
15	"unicode/utf8"
16)
17
18// A Func corresponds to a single function in a Go program
19// (and vice versa: each function is denoted by exactly one *Func).
20//
21// There are multiple nodes that represent a Func in the IR.
22//
23// The ONAME node (Func.Nname) is used for plain references to it.
24// The ODCLFUNC node (the Func itself) is used for its declaration code.
25// The OCLOSURE node (Func.OClosure) is used for a reference to a
26// function literal.
27//
28// An imported function will have an ONAME node which points to a Func
29// with an empty body.
30// A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
31// A function literal is represented directly by an OCLOSURE, but it also
32// has an ODCLFUNC (and a matching ONAME) representing the compiled
33// underlying form of the closure, which accesses the captured variables
34// using a special data structure passed in a register.
35//
36// A method declaration is represented like functions, except f.Sym
37// will be the qualified method name (e.g., "T.m").
38//
39// A method expression (T.M) is represented as an OMETHEXPR node,
40// in which n.Left and n.Right point to the type and method, respectively.
41// Each distinct mention of a method expression in the source code
42// constructs a fresh node.
43//
44// A method value (t.M) is represented by ODOTMETH/ODOTINTER
45// when it is called directly and by OMETHVALUE otherwise.
46// These are like method expressions, except that for ODOTMETH/ODOTINTER,
47// the method name is stored in Sym instead of Right.
48// Each OMETHVALUE ends up being implemented as a new
49// function, a bit like a closure, with its own ODCLFUNC.
50// The OMETHVALUE uses n.Func to record the linkage to
51// the generated ODCLFUNC, but there is no
52// pointer from the Func back to the OMETHVALUE.
53type Func struct {
54	miniNode
55	Body Nodes
56
57	Nname    *Name        // ONAME node
58	OClosure *ClosureExpr // OCLOSURE node
59
60	// ONAME nodes for all params/locals for this func/closure, does NOT
61	// include closurevars until transforming closures during walk.
62	// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
63	// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
64	// Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
65	Dcl []*Name
66
67	// ClosureVars lists the free variables that are used within a
68	// function literal, but formally declared in an enclosing
69	// function. The variables in this slice are the closure function's
70	// own copy of the variables, which are used within its function
71	// body. They will also each have IsClosureVar set, and will have
72	// Byval set if they're captured by value.
73	ClosureVars []*Name
74
75	// Enclosed functions that need to be compiled.
76	// Populated during walk.
77	Closures []*Func
78
79	// Parents records the parent scope of each scope within a
80	// function. The root scope (0) has no parent, so the i'th
81	// scope's parent is stored at Parents[i-1].
82	Parents []ScopeID
83
84	// Marks records scope boundary changes.
85	Marks []Mark
86
87	FieldTrack map[*obj.LSym]struct{}
88	DebugInfo  interface{}
89	LSym       *obj.LSym // Linker object in this function's native ABI (Func.ABI)
90
91	Inl *Inline
92
93	// RangeParent, if non-nil, is the first non-range body function containing
94	// the closure for the body of a range function.
95	RangeParent *Func
96
97	// funcLitGen, rangeLitGen and goDeferGen track how many closures have been
98	// created in this function for function literals, range-over-func loops,
99	// and go/defer wrappers, respectively. Used by closureName for creating
100	// unique function names.
101	// Tracking goDeferGen separately avoids wrappers throwing off
102	// function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
103	funcLitGen  int32
104	rangeLitGen int32
105	goDeferGen  int32
106
107	Label int32 // largest auto-generated label in this function
108
109	Endlineno src.XPos
110	WBPos     src.XPos // position of first write barrier; see SetWBPos
111
112	Pragma PragmaFlag // go:xxx function annotations
113
114	flags bitset16
115
116	// ABI is a function's "definition" ABI. This is the ABI that
117	// this function's generated code is expecting to be called by.
118	//
119	// For most functions, this will be obj.ABIInternal. It may be
120	// a different ABI for functions defined in assembly or ABI wrappers.
121	//
122	// This is included in the export data and tracked across packages.
123	ABI obj.ABI
124	// ABIRefs is the set of ABIs by which this function is referenced.
125	// For ABIs other than this function's definition ABI, the
126	// compiler generates ABI wrapper functions. This is only tracked
127	// within a package.
128	ABIRefs obj.ABISet
129
130	NumDefers  int32 // number of defer calls in the function
131	NumReturns int32 // number of explicit returns in the function
132
133	// NWBRCalls records the LSyms of functions called by this
134	// function for go:nowritebarrierrec analysis. Only filled in
135	// if nowritebarrierrecCheck != nil.
136	NWBRCalls *[]SymAndPos
137
138	// For wrapper functions, WrappedFunc point to the original Func.
139	// Currently only used for go/defer wrappers.
140	WrappedFunc *Func
141
142	// WasmImport is used by the //go:wasmimport directive to store info about
143	// a WebAssembly function import.
144	WasmImport *WasmImport
145}
146
147// WasmImport stores metadata associated with the //go:wasmimport pragma.
148type WasmImport struct {
149	Module string
150	Name   string
151}
152
153// NewFunc returns a new Func with the given name and type.
154//
155// fpos is the position of the "func" token, and npos is the position
156// of the name identifier.
157//
158// TODO(mdempsky): I suspect there's no need for separate fpos and
159// npos.
160func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
161	name := NewNameAt(npos, sym, typ)
162	name.Class = PFUNC
163	sym.SetFunc(true)
164
165	fn := &Func{Nname: name}
166	fn.pos = fpos
167	fn.op = ODCLFUNC
168	// Most functions are ABIInternal. The importer or symabis
169	// pass may override this.
170	fn.ABI = obj.ABIInternal
171	fn.SetTypecheck(1)
172
173	name.Func = fn
174
175	return fn
176}
177
178func (f *Func) isStmt() {}
179
180func (n *Func) copy() Node                                  { panic(n.no("copy")) }
181func (n *Func) doChildren(do func(Node) bool) bool          { return doNodes(n.Body, do) }
182func (n *Func) editChildren(edit func(Node) Node)           { editNodes(n.Body, edit) }
183func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
184
185func (f *Func) Type() *types.Type                { return f.Nname.Type() }
186func (f *Func) Sym() *types.Sym                  { return f.Nname.Sym() }
187func (f *Func) Linksym() *obj.LSym               { return f.Nname.Linksym() }
188func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
189
190// An Inline holds fields used for function bodies that can be inlined.
191type Inline struct {
192	Cost int32 // heuristic cost of inlining this function
193
194	// Copy of Func.Dcl for use during inlining. This copy is needed
195	// because the function's Dcl may change from later compiler
196	// transformations. This field is also populated when a function
197	// from another package is imported and inlined.
198	Dcl     []*Name
199	HaveDcl bool // whether we've loaded Dcl
200
201	// Function properties, encoded as a string (these are used for
202	// making inlining decisions). See cmd/compile/internal/inline/inlheur.
203	Properties string
204
205	// CanDelayResults reports whether it's safe for the inliner to delay
206	// initializing the result parameters until immediately before the
207	// "return" statement.
208	CanDelayResults bool
209}
210
211// A Mark represents a scope boundary.
212type Mark struct {
213	// Pos is the position of the token that marks the scope
214	// change.
215	Pos src.XPos
216
217	// Scope identifies the innermost scope to the right of Pos.
218	Scope ScopeID
219}
220
221// A ScopeID represents a lexical scope within a function.
222type ScopeID int32
223
224const (
225	funcDupok      = 1 << iota // duplicate definitions ok
226	funcWrapper                // hide frame from users (elide in tracebacks, don't count as a frame for recover())
227	funcABIWrapper             // is an ABI wrapper (also set flagWrapper)
228	funcNeedctxt               // function uses context register (has closure variables)
229	// true if closure inside a function; false if a simple function or a
230	// closure in a global variable initialization
231	funcIsHiddenClosure
232	funcIsDeadcodeClosure        // true if closure is deadcode
233	funcHasDefer                 // contains a defer statement
234	funcNilCheckDisabled         // disable nil checks when compiling this function
235	funcInlinabilityChecked      // inliner has already determined whether the function is inlinable
236	funcNeverReturns             // function never returns (in most cases calls panic(), os.Exit(), or equivalent)
237	funcOpenCodedDeferDisallowed // can't do open-coded defers
238	funcClosureResultsLost       // closure is called indirectly and we lost track of its results; used by escape analysis
239	funcPackageInit              // compiler emitted .init func for package
240)
241
242type SymAndPos struct {
243	Sym *obj.LSym // LSym of callee
244	Pos src.XPos  // line of call
245}
246
247func (f *Func) Dupok() bool                    { return f.flags&funcDupok != 0 }
248func (f *Func) Wrapper() bool                  { return f.flags&funcWrapper != 0 }
249func (f *Func) ABIWrapper() bool               { return f.flags&funcABIWrapper != 0 }
250func (f *Func) Needctxt() bool                 { return f.flags&funcNeedctxt != 0 }
251func (f *Func) IsHiddenClosure() bool          { return f.flags&funcIsHiddenClosure != 0 }
252func (f *Func) IsDeadcodeClosure() bool        { return f.flags&funcIsDeadcodeClosure != 0 }
253func (f *Func) HasDefer() bool                 { return f.flags&funcHasDefer != 0 }
254func (f *Func) NilCheckDisabled() bool         { return f.flags&funcNilCheckDisabled != 0 }
255func (f *Func) InlinabilityChecked() bool      { return f.flags&funcInlinabilityChecked != 0 }
256func (f *Func) NeverReturns() bool             { return f.flags&funcNeverReturns != 0 }
257func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
258func (f *Func) ClosureResultsLost() bool       { return f.flags&funcClosureResultsLost != 0 }
259func (f *Func) IsPackageInit() bool            { return f.flags&funcPackageInit != 0 }
260
261func (f *Func) SetDupok(b bool)                    { f.flags.set(funcDupok, b) }
262func (f *Func) SetWrapper(b bool)                  { f.flags.set(funcWrapper, b) }
263func (f *Func) SetABIWrapper(b bool)               { f.flags.set(funcABIWrapper, b) }
264func (f *Func) SetNeedctxt(b bool)                 { f.flags.set(funcNeedctxt, b) }
265func (f *Func) SetIsHiddenClosure(b bool)          { f.flags.set(funcIsHiddenClosure, b) }
266func (f *Func) SetIsDeadcodeClosure(b bool)        { f.flags.set(funcIsDeadcodeClosure, b) }
267func (f *Func) SetHasDefer(b bool)                 { f.flags.set(funcHasDefer, b) }
268func (f *Func) SetNilCheckDisabled(b bool)         { f.flags.set(funcNilCheckDisabled, b) }
269func (f *Func) SetInlinabilityChecked(b bool)      { f.flags.set(funcInlinabilityChecked, b) }
270func (f *Func) SetNeverReturns(b bool)             { f.flags.set(funcNeverReturns, b) }
271func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
272func (f *Func) SetClosureResultsLost(b bool)       { f.flags.set(funcClosureResultsLost, b) }
273func (f *Func) SetIsPackageInit(b bool)            { f.flags.set(funcPackageInit, b) }
274
275func (f *Func) SetWBPos(pos src.XPos) {
276	if base.Debug.WB != 0 {
277		base.WarnfAt(pos, "write barrier")
278	}
279	if !f.WBPos.IsKnown() {
280		f.WBPos = pos
281	}
282}
283
284// FuncName returns the name (without the package) of the function f.
285func FuncName(f *Func) string {
286	if f == nil || f.Nname == nil {
287		return "<nil>"
288	}
289	return f.Sym().Name
290}
291
292// PkgFuncName returns the name of the function referenced by f, with package
293// prepended.
294//
295// This differs from the compiler's internal convention where local functions
296// lack a package. This is primarily useful when the ultimate consumer of this
297// is a human looking at message.
298func PkgFuncName(f *Func) string {
299	if f == nil || f.Nname == nil {
300		return "<nil>"
301	}
302	s := f.Sym()
303	pkg := s.Pkg
304
305	return pkg.Path + "." + s.Name
306}
307
308// LinkFuncName returns the name of the function f, as it will appear in the
309// symbol table of the final linked binary.
310func LinkFuncName(f *Func) string {
311	if f == nil || f.Nname == nil {
312		return "<nil>"
313	}
314	s := f.Sym()
315	pkg := s.Pkg
316
317	return objabi.PathToPrefix(pkg.Path) + "." + s.Name
318}
319
320// ParseLinkFuncName parsers a symbol name (as returned from LinkFuncName) back
321// to the package path and local symbol name.
322func ParseLinkFuncName(name string) (pkg, sym string, err error) {
323	pkg, sym = splitPkg(name)
324	if pkg == "" {
325		return "", "", fmt.Errorf("no package path in name")
326	}
327
328	pkg, err = objabi.PrefixToPath(pkg) // unescape
329	if err != nil {
330		return "", "", fmt.Errorf("malformed package path: %v", err)
331	}
332
333	return pkg, sym, nil
334}
335
336// Borrowed from x/mod.
337func modPathOK(r rune) bool {
338	if r < utf8.RuneSelf {
339		return r == '-' || r == '.' || r == '_' || r == '~' ||
340			'0' <= r && r <= '9' ||
341			'A' <= r && r <= 'Z' ||
342			'a' <= r && r <= 'z'
343	}
344	return false
345}
346
347func escapedImportPathOK(r rune) bool {
348	return modPathOK(r) || r == '+' || r == '/' || r == '%'
349}
350
351// splitPkg splits the full linker symbol name into package and local symbol
352// name.
353func splitPkg(name string) (pkgpath, sym string) {
354	// package-sym split is at first dot after last the / that comes before
355	// any characters illegal in a package path.
356
357	lastSlashIdx := 0
358	for i, r := range name {
359		// Catches cases like:
360		// * example.foo[sync/atomic.Uint64].
361		// * example%2ecom.foo[sync/atomic.Uint64].
362		//
363		// Note that name is still escaped; unescape occurs after splitPkg.
364		if !escapedImportPathOK(r) {
365			break
366		}
367		if r == '/' {
368			lastSlashIdx = i
369		}
370	}
371	for i := lastSlashIdx; i < len(name); i++ {
372		r := name[i]
373		if r == '.' {
374			return name[:i], name[i+1:]
375		}
376	}
377
378	return "", name
379}
380
381var CurFunc *Func
382
383// WithFunc invokes do with CurFunc and base.Pos set to curfn and
384// curfn.Pos(), respectively, and then restores their previous values
385// before returning.
386func WithFunc(curfn *Func, do func()) {
387	oldfn, oldpos := CurFunc, base.Pos
388	defer func() { CurFunc, base.Pos = oldfn, oldpos }()
389
390	CurFunc, base.Pos = curfn, curfn.Pos()
391	do()
392}
393
394func FuncSymName(s *types.Sym) string {
395	return s.Name + "·f"
396}
397
398// ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
399// and compiling runtime.
400func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
401	if base.Debug.Closure > 0 {
402		if clo.Esc() == EscHeap {
403			base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
404		} else {
405			base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
406		}
407	}
408	if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
409		base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
410	}
411}
412
413// IsTrivialClosure reports whether closure clo has an
414// empty list of captured vars.
415func IsTrivialClosure(clo *ClosureExpr) bool {
416	return len(clo.Func.ClosureVars) == 0
417}
418
419// globClosgen is like Func.Closgen, but for the global scope.
420var globClosgen int32
421
422// closureName generates a new unique name for a closure within outerfn at pos.
423func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
424	if outerfn != nil && outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
425		outerfn = outerfn.OClosure.Func.RangeParent
426	}
427	pkg := types.LocalPkg
428	outer := "glob."
429	var suffix string = "."
430	switch why {
431	default:
432		base.FatalfAt(pos, "closureName: bad Op: %v", why)
433	case OCLOSURE:
434		if outerfn == nil || outerfn.OClosure == nil {
435			suffix = ".func"
436		}
437	case ORANGE:
438		suffix = "-range"
439	case OGO:
440		suffix = ".gowrap"
441	case ODEFER:
442		suffix = ".deferwrap"
443	}
444	gen := &globClosgen
445
446	// There may be multiple functions named "_". In those
447	// cases, we can't use their individual Closgens as it
448	// would lead to name clashes.
449	if outerfn != nil && !IsBlank(outerfn.Nname) {
450		pkg = outerfn.Sym().Pkg
451		outer = FuncName(outerfn)
452
453		switch why {
454		case OCLOSURE:
455			gen = &outerfn.funcLitGen
456		case ORANGE:
457			gen = &outerfn.rangeLitGen
458		default:
459			gen = &outerfn.goDeferGen
460		}
461	}
462
463	// If this closure was created due to inlining, then incorporate any
464	// inlined functions' names into the closure's linker symbol name
465	// too (#60324).
466	if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
467		names := []string{outer}
468		base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
469			names = append(names, call.Name)
470		})
471		outer = strings.Join(names, ".")
472	}
473
474	*gen++
475	return pkg.Lookup(fmt.Sprintf("%s%s%d", outer, suffix, *gen))
476}
477
478// NewClosureFunc creates a new Func to represent a function literal
479// with the given type.
480//
481// fpos the position used for the underlying ODCLFUNC and ONAME,
482// whereas cpos is the position used for the OCLOSURE. They're
483// separate because in the presence of inlining, the OCLOSURE node
484// should have an inline-adjusted position, whereas the ODCLFUNC and
485// ONAME must not.
486//
487// outerfn is the enclosing function, if any. The returned function is
488// appending to pkg.Funcs.
489//
490// why is the reason we're generating this Func. It can be OCLOSURE
491// (for a normal function literal) or OGO or ODEFER (for wrapping a
492// call expression that has parameters or results).
493func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package) *Func {
494	fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why), typ)
495	fn.SetIsHiddenClosure(outerfn != nil)
496	if outerfn != nil {
497		fn.SetDupok(outerfn.Dupok()) // if the outer function is dupok, so is the closure
498	}
499
500	clo := &ClosureExpr{Func: fn}
501	clo.op = OCLOSURE
502	clo.pos = cpos
503	clo.SetType(typ)
504	clo.SetTypecheck(1)
505	if why == ORANGE {
506		clo.Func.RangeParent = outerfn
507		if outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
508			clo.Func.RangeParent = outerfn.OClosure.Func.RangeParent
509		}
510	}
511	fn.OClosure = clo
512
513	fn.Nname.Defn = fn
514	pkg.Funcs = append(pkg.Funcs, fn)
515
516	return fn
517}
518
519// IsFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
520func IsFuncPCIntrinsic(n *CallExpr) bool {
521	if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
522		return false
523	}
524	fn := n.Fun.(*Name).Sym()
525	return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
526		fn.Pkg.Path == "internal/abi"
527}
528
529// IsIfaceOfFunc inspects whether n is an interface conversion from a direct
530// reference of a func. If so, it returns referenced Func; otherwise nil.
531//
532// This is only usable before walk.walkConvertInterface, which converts to an
533// OMAKEFACE.
534func IsIfaceOfFunc(n Node) *Func {
535	if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
536		if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
537			return name.Func
538		}
539	}
540	return nil
541}
542
543// FuncPC returns a uintptr-typed expression that evaluates to the PC of a
544// function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
545//
546// n should be a Node of an interface type, as is passed to
547// internal/abi.FuncPC{ABI0,ABIInternal}.
548//
549// TODO(prattmic): Since n is simply an interface{} there is no assertion that
550// it is actually a function at all. Perhaps we should emit a runtime type
551// assertion?
552func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
553	if !n.Type().IsInterface() {
554		base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
555	}
556
557	if fn := IsIfaceOfFunc(n); fn != nil {
558		name := fn.Nname
559		abi := fn.ABI
560		if abi != wantABI {
561			base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
562		}
563		var e Node = NewLinksymExpr(pos, name.LinksymABI(abi), types.Types[types.TUINTPTR])
564		e = NewAddrExpr(pos, e)
565		e.SetType(types.Types[types.TUINTPTR].PtrTo())
566		e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
567		e.SetTypecheck(1)
568		return e
569	}
570	// fn is not a defined function. It must be ABIInternal.
571	// Read the address from func value, i.e. *(*uintptr)(idata(fn)).
572	if wantABI != obj.ABIInternal {
573		base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
574	}
575	var e Node = NewUnaryExpr(pos, OIDATA, n)
576	e.SetType(types.Types[types.TUINTPTR].PtrTo())
577	e.SetTypecheck(1)
578	e = NewStarExpr(pos, e)
579	e.SetType(types.Types[types.TUINTPTR])
580	e.SetTypecheck(1)
581	return e
582}
583
584// DeclareParams creates Names for all of the parameters in fn's
585// signature and adds them to fn.Dcl.
586//
587// If setNname is true, then it also sets types.Field.Nname for each
588// parameter.
589func (fn *Func) DeclareParams(setNname bool) {
590	if fn.Dcl != nil {
591		base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
592	}
593
594	declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
595		for i, param := range params {
596			sym := param.Sym
597			if sym == nil || sym.IsBlank() {
598				sym = fn.Sym().Pkg.LookupNum(prefix, i)
599			}
600
601			name := NewNameAt(param.Pos, sym, param.Type)
602			name.Class = ctxt
603			name.Curfn = fn
604			fn.Dcl[offset+i] = name
605
606			if setNname {
607				param.Nname = name
608			}
609		}
610	}
611
612	sig := fn.Type()
613	params := sig.RecvParams()
614	results := sig.Results()
615
616	fn.Dcl = make([]*Name, len(params)+len(results))
617	declareParams(params, PPARAM, "~p", 0)
618	declareParams(results, PPARAMOUT, "~r", len(params))
619}
620