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