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