github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/reader.go (about) 1 // Copyright 2021 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 noder 6 7 import ( 8 "fmt" 9 "github.com/bir3/gocompiler/src/go/constant" 10 "github.com/bir3/gocompiler/src/internal/buildcfg" 11 "github.com/bir3/gocompiler/src/internal/pkgbits" 12 "strings" 13 14 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 15 "github.com/bir3/gocompiler/src/cmd/compile/internal/deadcode" 16 "github.com/bir3/gocompiler/src/cmd/compile/internal/dwarfgen" 17 "github.com/bir3/gocompiler/src/cmd/compile/internal/inline" 18 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 19 "github.com/bir3/gocompiler/src/cmd/compile/internal/objw" 20 "github.com/bir3/gocompiler/src/cmd/compile/internal/reflectdata" 21 "github.com/bir3/gocompiler/src/cmd/compile/internal/staticinit" 22 "github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck" 23 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 24 "github.com/bir3/gocompiler/src/cmd/internal/obj" 25 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 26 "github.com/bir3/gocompiler/src/cmd/internal/src" 27 ) 28 29 // This file implements cmd/compile backend's reader for the Unified 30 // IR export data. 31 32 // A pkgReader reads Unified IR export data. 33 type pkgReader struct { 34 pkgbits.PkgDecoder 35 36 // Indices for encoded things; lazily populated as needed. 37 // 38 // Note: Objects (i.e., ir.Names) are lazily instantiated by 39 // populating their types.Sym.Def; see objReader below. 40 41 posBases []*src.PosBase 42 pkgs []*types.Pkg 43 typs []*types.Type 44 45 // offset for rewriting the given (absolute!) index into the output, 46 // but bitwise inverted so we can detect if we're missing the entry 47 // or not. 48 newindex []pkgbits.Index 49 } 50 51 func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader { 52 return &pkgReader{ 53 PkgDecoder: pr, 54 55 posBases: make([]*src.PosBase, pr.NumElems(pkgbits.RelocPosBase)), 56 pkgs: make([]*types.Pkg, pr.NumElems(pkgbits.RelocPkg)), 57 typs: make([]*types.Type, pr.NumElems(pkgbits.RelocType)), 58 59 newindex: make([]pkgbits.Index, pr.TotalElems()), 60 } 61 } 62 63 // A pkgReaderIndex compactly identifies an index (and its 64 // corresponding dictionary) within a package's export data. 65 type pkgReaderIndex struct { 66 pr *pkgReader 67 idx pkgbits.Index 68 dict *readerDict 69 methodSym *types.Sym 70 71 synthetic func(pos src.XPos, r *reader) 72 } 73 74 func (pri pkgReaderIndex) asReader(k pkgbits.RelocKind, marker pkgbits.SyncMarker) *reader { 75 if pri.synthetic != nil { 76 return &reader{synthetic: pri.synthetic} 77 } 78 79 r := pri.pr.newReader(k, pri.idx, marker) 80 r.dict = pri.dict 81 r.methodSym = pri.methodSym 82 return r 83 } 84 85 func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { 86 return &reader{ 87 Decoder: pr.NewDecoder(k, idx, marker), 88 p: pr, 89 } 90 } 91 92 // A reader provides APIs for reading an individual element. 93 type reader struct { 94 pkgbits.Decoder 95 96 p *pkgReader 97 98 dict *readerDict 99 100 // TODO(mdempsky): The state below is all specific to reading 101 // function bodies. It probably makes sense to split it out 102 // separately so that it doesn't take up space in every reader 103 // instance. 104 105 curfn *ir.Func 106 locals []*ir.Name 107 closureVars []*ir.Name 108 109 funarghack bool 110 111 // methodSym is the name of method's name, if reading a method. 112 // It's nil if reading a normal function or closure body. 113 methodSym *types.Sym 114 115 // dictParam is the .dict param, if any. 116 dictParam *ir.Name 117 118 // synthetic is a callback function to construct a synthetic 119 // function body. It's used for creating the bodies of function 120 // literals used to curry arguments to shaped functions. 121 synthetic func(pos src.XPos, r *reader) 122 123 // scopeVars is a stack tracking the number of variables declared in 124 // the current function at the moment each open scope was opened. 125 scopeVars []int 126 marker dwarfgen.ScopeMarker 127 lastCloseScopePos src.XPos 128 129 // === details for handling inline body expansion === 130 131 // If we're reading in a function body because of inlining, this is 132 // the call that we're inlining for. 133 inlCaller *ir.Func 134 inlCall *ir.CallExpr 135 inlFunc *ir.Func 136 inlTreeIndex int 137 inlPosBases map[*src.PosBase]*src.PosBase 138 139 // suppressInlPos tracks whether position base rewriting for 140 // inlining should be suppressed. See funcLit. 141 suppressInlPos int 142 143 delayResults bool 144 145 // Label to return to. 146 retlabel *types.Sym 147 148 // inlvars is the list of variables that the inlinee's arguments are 149 // assigned to, one for each receiver and normal parameter, in order. 150 inlvars ir.Nodes 151 152 // retvars is the list of variables that the inlinee's results are 153 // assigned to, one for each result parameter, in order. 154 retvars ir.Nodes 155 } 156 157 // A readerDict represents an instantiated "compile-time dictionary," 158 // used for resolving any derived types needed for instantiating a 159 // generic object. 160 // 161 // A compile-time dictionary can either be "shaped" or "non-shaped." 162 // Shaped compile-time dictionaries are only used for instantiating 163 // shaped type definitions and function bodies, while non-shaped 164 // compile-time dictionaries are used for instantiating runtime 165 // dictionaries. 166 type readerDict struct { 167 shaped bool // whether this is a shaped dictionary 168 169 // baseSym is the symbol for the object this dictionary belongs to. 170 // If the object is an instantiated function or defined type, then 171 // baseSym is the mangled symbol, including any type arguments. 172 baseSym *types.Sym 173 174 // For non-shaped dictionaries, shapedObj is a reference to the 175 // corresponding shaped object (always a function or defined type). 176 shapedObj *ir.Name 177 178 // targs holds the implicit and explicit type arguments in use for 179 // reading the current object. For example: 180 // 181 // func F[T any]() { 182 // type X[U any] struct { t T; u U } 183 // var _ X[string] 184 // } 185 // 186 // var _ = F[int] 187 // 188 // While instantiating F[int], we need to in turn instantiate 189 // X[string]. [int] and [string] are explicit type arguments for F 190 // and X, respectively; but [int] is also the implicit type 191 // arguments for X. 192 // 193 // (As an analogy to function literals, explicits are the function 194 // literal's formal parameters, while implicits are variables 195 // captured by the function literal.) 196 targs []*types.Type 197 198 // implicits counts how many of types within targs are implicit type 199 // arguments; the rest are explicit. 200 implicits int 201 202 derived []derivedInfo // reloc index of the derived type's descriptor 203 derivedTypes []*types.Type // slice of previously computed derived types 204 205 // These slices correspond to entries in the runtime dictionary. 206 typeParamMethodExprs []readerMethodExprInfo 207 subdicts []objInfo 208 rtypes []typeInfo 209 itabs []itabInfo 210 } 211 212 type readerMethodExprInfo struct { 213 typeParamIdx int 214 method *types.Sym 215 } 216 217 func setType(n ir.Node, typ *types.Type) { 218 n.SetType(typ) 219 n.SetTypecheck(1) 220 } 221 222 func setValue(name *ir.Name, val constant.Value) { 223 name.SetVal(val) 224 name.Defn = nil 225 } 226 227 // @@@ Positions 228 229 // pos reads a position from the bitstream. 230 func (r *reader) pos() src.XPos { 231 return base.Ctxt.PosTable.XPos(r.pos0()) 232 } 233 234 // origPos reads a position from the bitstream, and returns both the 235 // original raw position and an inlining-adjusted position. 236 func (r *reader) origPos() (origPos, inlPos src.XPos) { 237 r.suppressInlPos++ 238 origPos = r.pos() 239 r.suppressInlPos-- 240 inlPos = r.inlPos(origPos) 241 return 242 } 243 244 func (r *reader) pos0() src.Pos { 245 r.Sync(pkgbits.SyncPos) 246 if !r.Bool() { 247 return src.NoPos 248 } 249 250 posBase := r.posBase() 251 line := r.Uint() 252 col := r.Uint() 253 return src.MakePos(posBase, line, col) 254 } 255 256 // posBase reads a position base from the bitstream. 257 func (r *reader) posBase() *src.PosBase { 258 return r.inlPosBase(r.p.posBaseIdx(r.Reloc(pkgbits.RelocPosBase))) 259 } 260 261 // posBaseIdx returns the specified position base, reading it first if 262 // needed. 263 func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) *src.PosBase { 264 if b := pr.posBases[idx]; b != nil { 265 return b 266 } 267 268 r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) 269 var b *src.PosBase 270 271 absFilename := r.String() 272 filename := absFilename 273 274 // For build artifact stability, the export data format only 275 // contains the "absolute" filename as returned by objabi.AbsFile. 276 // However, some tests (e.g., test/run.go's asmcheck tests) expect 277 // to see the full, original filename printed out. Re-expanding 278 // "$GOROOT" to buildcfg.GOROOT is a close-enough approximation to 279 // satisfy this. 280 // 281 // TODO(mdempsky): De-duplicate this logic with similar logic in 282 // cmd/link/internal/ld's expandGoroot. However, this will probably 283 // require being more consistent about when we use native vs UNIX 284 // file paths. 285 const dollarGOROOT = "$GOROOT" 286 if buildcfg.GOROOT != "" && strings.HasPrefix(filename, dollarGOROOT) { 287 filename = buildcfg.GOROOT + filename[len(dollarGOROOT):] 288 } 289 290 if r.Bool() { 291 b = src.NewFileBase(filename, absFilename) 292 } else { 293 pos := r.pos0() 294 line := r.Uint() 295 col := r.Uint() 296 b = src.NewLinePragmaBase(pos, filename, absFilename, line, col) 297 } 298 299 pr.posBases[idx] = b 300 return b 301 } 302 303 // inlPosBase returns the inlining-adjusted src.PosBase corresponding 304 // to oldBase, which must be a non-inlined position. When not 305 // inlining, this is just oldBase. 306 func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase { 307 if index := oldBase.InliningIndex(); index >= 0 { 308 base.Fatalf("oldBase %v already has inlining index %v", oldBase, index) 309 } 310 311 if r.inlCall == nil || r.suppressInlPos != 0 { 312 return oldBase 313 } 314 315 if newBase, ok := r.inlPosBases[oldBase]; ok { 316 return newBase 317 } 318 319 newBase := src.NewInliningBase(oldBase, r.inlTreeIndex) 320 r.inlPosBases[oldBase] = newBase 321 return newBase 322 } 323 324 // inlPos returns the inlining-adjusted src.XPos corresponding to 325 // xpos, which must be a non-inlined position. When not inlining, this 326 // is just xpos. 327 func (r *reader) inlPos(xpos src.XPos) src.XPos { 328 pos := base.Ctxt.PosTable.Pos(xpos) 329 pos.SetBase(r.inlPosBase(pos.Base())) 330 return base.Ctxt.PosTable.XPos(pos) 331 } 332 333 // @@@ Packages 334 335 // pkg reads a package reference from the bitstream. 336 func (r *reader) pkg() *types.Pkg { 337 r.Sync(pkgbits.SyncPkg) 338 return r.p.pkgIdx(r.Reloc(pkgbits.RelocPkg)) 339 } 340 341 // pkgIdx returns the specified package from the export data, reading 342 // it first if needed. 343 func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types.Pkg { 344 if pkg := pr.pkgs[idx]; pkg != nil { 345 return pkg 346 } 347 348 pkg := pr.newReader(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef).doPkg() 349 pr.pkgs[idx] = pkg 350 return pkg 351 } 352 353 // doPkg reads a package definition from the bitstream. 354 func (r *reader) doPkg() *types.Pkg { 355 path := r.String() 356 switch path { 357 case "": 358 path = r.p.PkgPath() 359 case "builtin": 360 return types.BuiltinPkg 361 case "unsafe": 362 return types.UnsafePkg 363 } 364 365 name := r.String() 366 367 pkg := types.NewPkg(path, "") 368 369 if pkg.Name == "" { 370 pkg.Name = name 371 } else { 372 base.Assertf(pkg.Name == name, "package %q has name %q, but want %q", pkg.Path, pkg.Name, name) 373 } 374 375 return pkg 376 } 377 378 // @@@ Types 379 380 func (r *reader) typ() *types.Type { 381 return r.typWrapped(true) 382 } 383 384 // typWrapped is like typ, but allows suppressing generation of 385 // unnecessary wrappers as a compile-time optimization. 386 func (r *reader) typWrapped(wrapped bool) *types.Type { 387 return r.p.typIdx(r.typInfo(), r.dict, wrapped) 388 } 389 390 func (r *reader) typInfo() typeInfo { 391 r.Sync(pkgbits.SyncType) 392 if r.Bool() { 393 return typeInfo{idx: pkgbits.Index(r.Len()), derived: true} 394 } 395 return typeInfo{idx: r.Reloc(pkgbits.RelocType), derived: false} 396 } 397 398 // typListIdx returns a list of the specified types, resolving derived 399 // types within the given dictionary. 400 func (pr *pkgReader) typListIdx(infos []typeInfo, dict *readerDict) []*types.Type { 401 typs := make([]*types.Type, len(infos)) 402 for i, info := range infos { 403 typs[i] = pr.typIdx(info, dict, true) 404 } 405 return typs 406 } 407 408 // typIdx returns the specified type. If info specifies a derived 409 // type, it's resolved within the given dictionary. If wrapped is 410 // true, then method wrappers will be generated, if appropriate. 411 func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *types.Type { 412 idx := info.idx 413 var where **types.Type 414 if info.derived { 415 where = &dict.derivedTypes[idx] 416 idx = dict.derived[idx].idx 417 } else { 418 where = &pr.typs[idx] 419 } 420 421 if typ := *where; typ != nil { 422 return typ 423 } 424 425 r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) 426 r.dict = dict 427 428 typ := r.doTyp() 429 assert(typ != nil) 430 431 // For recursive type declarations involving interfaces and aliases, 432 // above r.doTyp() call may have already set pr.typs[idx], so just 433 // double check and return the type. 434 // 435 // Example: 436 // 437 // type F = func(I) 438 // 439 // type I interface { 440 // m(F) 441 // } 442 // 443 // The writer writes data types in following index order: 444 // 445 // 0: func(I) 446 // 1: I 447 // 2: interface{m(func(I))} 448 // 449 // The reader resolves it in following index order: 450 // 451 // 0 -> 1 -> 2 -> 0 -> 1 452 // 453 // and can divide in logically 2 steps: 454 // 455 // - 0 -> 1 : first time the reader reach type I, 456 // it creates new named type with symbol I. 457 // 458 // - 2 -> 0 -> 1: the reader ends up reaching symbol I again, 459 // now the symbol I was setup in above step, so 460 // the reader just return the named type. 461 // 462 // Now, the functions called return, the pr.typs looks like below: 463 // 464 // - 0 -> 1 -> 2 -> 0 : [<T> I <T>] 465 // - 0 -> 1 -> 2 : [func(I) I <T>] 466 // - 0 -> 1 : [func(I) I interface { "".m(func("".I)) }] 467 // 468 // The idx 1, corresponding with type I was resolved successfully 469 // after r.doTyp() call. 470 471 if prev := *where; prev != nil { 472 return prev 473 } 474 475 if wrapped { 476 // Only cache if we're adding wrappers, so that other callers that 477 // find a cached type know it was wrapped. 478 *where = typ 479 480 r.needWrapper(typ) 481 } 482 483 if !typ.IsUntyped() { 484 types.CheckSize(typ) 485 } 486 487 return typ 488 } 489 490 func (r *reader) doTyp() *types.Type { 491 switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag { 492 default: 493 panic(fmt.Sprintf("unexpected type: %v", tag)) 494 495 case pkgbits.TypeBasic: 496 return *basics[r.Len()] 497 498 case pkgbits.TypeNamed: 499 obj := r.obj() 500 assert(obj.Op() == ir.OTYPE) 501 return obj.Type() 502 503 case pkgbits.TypeTypeParam: 504 return r.dict.targs[r.Len()] 505 506 case pkgbits.TypeArray: 507 len := int64(r.Uint64()) 508 return types.NewArray(r.typ(), len) 509 case pkgbits.TypeChan: 510 dir := dirs[r.Len()] 511 return types.NewChan(r.typ(), dir) 512 case pkgbits.TypeMap: 513 return types.NewMap(r.typ(), r.typ()) 514 case pkgbits.TypePointer: 515 return types.NewPtr(r.typ()) 516 case pkgbits.TypeSignature: 517 return r.signature(types.LocalPkg, nil) 518 case pkgbits.TypeSlice: 519 return types.NewSlice(r.typ()) 520 case pkgbits.TypeStruct: 521 return r.structType() 522 case pkgbits.TypeInterface: 523 return r.interfaceType() 524 case pkgbits.TypeUnion: 525 return r.unionType() 526 } 527 } 528 529 func (r *reader) unionType() *types.Type { 530 // In the types1 universe, we only need to handle value types. 531 // Impure interfaces (i.e., interfaces with non-trivial type sets 532 // like "int | string") can only appear as type parameter bounds, 533 // and this is enforced by the types2 type checker. 534 // 535 // However, type unions can still appear in pure interfaces if the 536 // type union is equivalent to "any". E.g., typeparam/issue52124.go 537 // declares variables with the type "interface { any | int }". 538 // 539 // To avoid needing to represent type unions in types1 (since we 540 // don't have any uses for that today anyway), we simply fold them 541 // to "any". As a consistency check, we still read the union terms 542 // to make sure this substitution is safe. 543 544 pure := false 545 for i, n := 0, r.Len(); i < n; i++ { 546 _ = r.Bool() // tilde 547 term := r.typ() 548 if term.IsEmptyInterface() { 549 pure = true 550 } 551 } 552 if !pure { 553 base.Fatalf("impure type set used in value type") 554 } 555 556 return types.Types[types.TINTER] 557 } 558 559 func (r *reader) interfaceType() *types.Type { 560 tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone. 561 562 nmethods, nembeddeds := r.Len(), r.Len() 563 implicit := nmethods == 0 && nembeddeds == 1 && r.Bool() 564 assert(!implicit) // implicit interfaces only appear in constraints 565 566 fields := make([]*types.Field, nmethods+nembeddeds) 567 methods, embeddeds := fields[:nmethods], fields[nmethods:] 568 569 for i := range methods { 570 pos := r.pos() 571 pkg, sym := r.selector() 572 tpkg = pkg 573 mtyp := r.signature(pkg, types.FakeRecv()) 574 methods[i] = types.NewField(pos, sym, mtyp) 575 } 576 for i := range embeddeds { 577 embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ()) 578 } 579 580 if len(fields) == 0 { 581 return types.Types[types.TINTER] // empty interface 582 } 583 return types.NewInterface(tpkg, fields, false) 584 } 585 586 func (r *reader) structType() *types.Type { 587 tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone. 588 fields := make([]*types.Field, r.Len()) 589 for i := range fields { 590 pos := r.pos() 591 pkg, sym := r.selector() 592 tpkg = pkg 593 ftyp := r.typ() 594 tag := r.String() 595 embedded := r.Bool() 596 597 f := types.NewField(pos, sym, ftyp) 598 f.Note = tag 599 if embedded { 600 f.Embedded = 1 601 } 602 fields[i] = f 603 } 604 return types.NewStruct(tpkg, fields) 605 } 606 607 func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type { 608 r.Sync(pkgbits.SyncSignature) 609 610 params := r.params(&tpkg) 611 results := r.params(&tpkg) 612 if r.Bool() { // variadic 613 params[len(params)-1].SetIsDDD(true) 614 } 615 616 return types.NewSignature(tpkg, recv, nil, params, results) 617 } 618 619 func (r *reader) params(tpkg **types.Pkg) []*types.Field { 620 r.Sync(pkgbits.SyncParams) 621 fields := make([]*types.Field, r.Len()) 622 for i := range fields { 623 *tpkg, fields[i] = r.param() 624 } 625 return fields 626 } 627 628 func (r *reader) param() (*types.Pkg, *types.Field) { 629 r.Sync(pkgbits.SyncParam) 630 631 pos := r.pos() 632 pkg, sym := r.localIdent() 633 typ := r.typ() 634 635 return pkg, types.NewField(pos, sym, typ) 636 } 637 638 // @@@ Objects 639 640 // objReader maps qualified identifiers (represented as *types.Sym) to 641 // a pkgReader and corresponding index that can be used for reading 642 // that object's definition. 643 var objReader = map[*types.Sym]pkgReaderIndex{} 644 645 // obj reads an instantiated object reference from the bitstream. 646 func (r *reader) obj() ir.Node { 647 return r.p.objInstIdx(r.objInfo(), r.dict, false) 648 } 649 650 // objInfo reads an instantiated object reference from the bitstream 651 // and returns the encoded reference to it, without instantiating it. 652 func (r *reader) objInfo() objInfo { 653 r.Sync(pkgbits.SyncObject) 654 assert(!r.Bool()) // TODO(mdempsky): Remove; was derived func inst. 655 idx := r.Reloc(pkgbits.RelocObj) 656 657 explicits := make([]typeInfo, r.Len()) 658 for i := range explicits { 659 explicits[i] = r.typInfo() 660 } 661 662 return objInfo{idx, explicits} 663 } 664 665 // objInstIdx returns the encoded, instantiated object. If shaped is 666 // true, then the shaped variant of the object is returned instead. 667 func (pr *pkgReader) objInstIdx(info objInfo, dict *readerDict, shaped bool) ir.Node { 668 explicits := pr.typListIdx(info.explicits, dict) 669 670 var implicits []*types.Type 671 if dict != nil { 672 implicits = dict.targs 673 } 674 675 return pr.objIdx(info.idx, implicits, explicits, shaped) 676 } 677 678 // objIdx returns the specified object, instantiated with the given 679 // type arguments, if any. If shaped is true, then the shaped variant 680 // of the object is returned instead. 681 func (pr *pkgReader) objIdx(idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) ir.Node { 682 rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) 683 _, sym := rname.qualifiedIdent() 684 tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) 685 686 if tag == pkgbits.ObjStub { 687 assert(!sym.IsBlank()) 688 switch sym.Pkg { 689 case types.BuiltinPkg, types.UnsafePkg: 690 return sym.Def.(ir.Node) 691 } 692 if pri, ok := objReader[sym]; ok { 693 return pri.pr.objIdx(pri.idx, nil, explicits, shaped) 694 } 695 base.Fatalf("unresolved stub: %v", sym) 696 } 697 698 dict := pr.objDictIdx(sym, idx, implicits, explicits, shaped) 699 700 sym = dict.baseSym 701 if !sym.IsBlank() && sym.Def != nil { 702 return sym.Def.(*ir.Name) 703 } 704 705 r := pr.newReader(pkgbits.RelocObj, idx, pkgbits.SyncObject1) 706 rext := pr.newReader(pkgbits.RelocObjExt, idx, pkgbits.SyncObject1) 707 708 r.dict = dict 709 rext.dict = dict 710 711 do := func(op ir.Op, hasTParams bool) *ir.Name { 712 pos := r.pos() 713 setBasePos(pos) 714 if hasTParams { 715 r.typeParamNames() 716 } 717 718 name := ir.NewDeclNameAt(pos, op, sym) 719 name.Class = ir.PEXTERN // may be overridden later 720 if !sym.IsBlank() { 721 if sym.Def != nil { 722 base.FatalfAt(name.Pos(), "already have a definition for %v", name) 723 } 724 assert(sym.Def == nil) 725 sym.Def = name 726 } 727 return name 728 } 729 730 switch tag { 731 default: 732 panic("unexpected object") 733 734 case pkgbits.ObjAlias: 735 name := do(ir.OTYPE, false) 736 setType(name, r.typ()) 737 name.SetAlias(true) 738 return name 739 740 case pkgbits.ObjConst: 741 name := do(ir.OLITERAL, false) 742 typ := r.typ() 743 val := FixValue(typ, r.Value()) 744 setType(name, typ) 745 setValue(name, val) 746 return name 747 748 case pkgbits.ObjFunc: 749 if sym.Name == "init" { 750 sym = Renameinit() 751 } 752 name := do(ir.ONAME, true) 753 setType(name, r.signature(sym.Pkg, nil)) 754 755 name.Func = ir.NewFunc(r.pos()) 756 name.Func.Nname = name 757 758 if r.hasTypeParams() { 759 name.Func.SetDupok(true) 760 if r.dict.shaped { 761 setType(name, shapeSig(name.Func, r.dict)) 762 } else { 763 todoDicts = append(todoDicts, func() { 764 r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name) 765 }) 766 } 767 } 768 769 rext.funcExt(name, nil) 770 return name 771 772 case pkgbits.ObjType: 773 name := do(ir.OTYPE, true) 774 typ := types.NewNamed(name) 775 setType(name, typ) 776 if r.hasTypeParams() && r.dict.shaped { 777 typ.SetHasShape(true) 778 } 779 780 // Important: We need to do this before SetUnderlying. 781 rext.typeExt(name) 782 783 // We need to defer CheckSize until we've called SetUnderlying to 784 // handle recursive types. 785 types.DeferCheckSize() 786 typ.SetUnderlying(r.typWrapped(false)) 787 types.ResumeCheckSize() 788 789 if r.hasTypeParams() && !r.dict.shaped { 790 todoDicts = append(todoDicts, func() { 791 r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name) 792 }) 793 } 794 795 methods := make([]*types.Field, r.Len()) 796 for i := range methods { 797 methods[i] = r.method(rext) 798 } 799 if len(methods) != 0 { 800 typ.Methods().Set(methods) 801 } 802 803 if !r.dict.shaped { 804 r.needWrapper(typ) 805 } 806 807 return name 808 809 case pkgbits.ObjVar: 810 name := do(ir.ONAME, false) 811 setType(name, r.typ()) 812 rext.varExt(name) 813 return name 814 } 815 } 816 817 func (dict *readerDict) mangle(sym *types.Sym) *types.Sym { 818 if !dict.hasTypeParams() { 819 return sym 820 } 821 822 // If sym is a locally defined generic type, we need the suffix to 823 // stay at the end after mangling so that types/fmt.go can strip it 824 // out again when writing the type's runtime descriptor (#54456). 825 base, suffix := types.SplitVargenSuffix(sym.Name) 826 827 var buf strings.Builder 828 buf.WriteString(base) 829 buf.WriteByte('[') 830 for i, targ := range dict.targs { 831 if i > 0 { 832 if i == dict.implicits { 833 buf.WriteByte(';') 834 } else { 835 buf.WriteByte(',') 836 } 837 } 838 buf.WriteString(targ.LinkString()) 839 } 840 buf.WriteByte(']') 841 buf.WriteString(suffix) 842 return sym.Pkg.Lookup(buf.String()) 843 } 844 845 // shapify returns the shape type for targ. 846 // 847 // If basic is true, then the type argument is used to instantiate a 848 // type parameter whose constraint is a basic interface. 849 func shapify(targ *types.Type, basic bool) *types.Type { 850 if targ.Kind() == types.TFORW { 851 if targ.IsFullyInstantiated() { 852 // For recursive instantiated type argument, it may still be a TFORW 853 // when shapifying happens. If we don't have targ's underlying type, 854 // shapify won't work. The worst case is we end up not reusing code 855 // optimally in some tricky cases. 856 if base.Debug.Shapify != 0 { 857 base.Warn("skipping shaping of recursive type %v", targ) 858 } 859 if targ.HasShape() { 860 return targ 861 } 862 } else { 863 base.Fatalf("%v is missing its underlying type", targ) 864 } 865 } 866 867 // When a pointer type is used to instantiate a type parameter 868 // constrained by a basic interface, we know the pointer's element 869 // type can't matter to the generated code. In this case, we can use 870 // an arbitrary pointer type as the shape type. (To match the 871 // non-unified frontend, we use `*byte`.) 872 // 873 // Otherwise, we simply use the type's underlying type as its shape. 874 // 875 // TODO(mdempsky): It should be possible to do much more aggressive 876 // shaping still; e.g., collapsing all pointer-shaped types into a 877 // common type, collapsing scalars of the same size/alignment into a 878 // common type, recursively shaping the element types of composite 879 // types, and discarding struct field names and tags. However, we'll 880 // need to start tracking how type parameters are actually used to 881 // implement some of these optimizations. 882 under := targ.Underlying() 883 if basic && targ.IsPtr() && !targ.Elem().NotInHeap() { 884 under = types.NewPtr(types.Types[types.TUINT8]) 885 } 886 887 sym := types.ShapePkg.Lookup(under.LinkString()) 888 if sym.Def == nil { 889 name := ir.NewDeclNameAt(under.Pos(), ir.OTYPE, sym) 890 typ := types.NewNamed(name) 891 typ.SetUnderlying(under) 892 sym.Def = typed(typ, name) 893 } 894 res := sym.Def.Type() 895 assert(res.IsShape()) 896 assert(res.HasShape()) 897 return res 898 } 899 900 // objDictIdx reads and returns the specified object dictionary. 901 func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, explicits []*types.Type, shaped bool) *readerDict { 902 r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) 903 904 dict := readerDict{ 905 shaped: shaped, 906 } 907 908 nimplicits := r.Len() 909 nexplicits := r.Len() 910 911 if nimplicits > len(implicits) || nexplicits != len(explicits) { 912 base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits)) 913 } 914 915 dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) 916 dict.implicits = nimplicits 917 918 // Within the compiler, we can just skip over the type parameters. 919 for range dict.targs[dict.implicits:] { 920 // Skip past bounds without actually evaluating them. 921 r.typInfo() 922 } 923 924 dict.derived = make([]derivedInfo, r.Len()) 925 dict.derivedTypes = make([]*types.Type, len(dict.derived)) 926 for i := range dict.derived { 927 dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} 928 } 929 930 // Runtime dictionary information; private to the compiler. 931 932 // If any type argument is already shaped, then we're constructing a 933 // shaped object, even if not explicitly requested (i.e., calling 934 // objIdx with shaped==true). This can happen with instantiating 935 // types that are referenced within a function body. 936 for _, targ := range dict.targs { 937 if targ.HasShape() { 938 dict.shaped = true 939 break 940 } 941 } 942 943 // And if we're constructing a shaped object, then shapify all type 944 // arguments. 945 for i, targ := range dict.targs { 946 basic := r.Bool() 947 if dict.shaped { 948 dict.targs[i] = shapify(targ, basic) 949 } 950 } 951 952 dict.baseSym = dict.mangle(sym) 953 954 dict.typeParamMethodExprs = make([]readerMethodExprInfo, r.Len()) 955 for i := range dict.typeParamMethodExprs { 956 typeParamIdx := r.Len() 957 _, method := r.selector() 958 959 dict.typeParamMethodExprs[i] = readerMethodExprInfo{typeParamIdx, method} 960 } 961 962 dict.subdicts = make([]objInfo, r.Len()) 963 for i := range dict.subdicts { 964 dict.subdicts[i] = r.objInfo() 965 } 966 967 dict.rtypes = make([]typeInfo, r.Len()) 968 for i := range dict.rtypes { 969 dict.rtypes[i] = r.typInfo() 970 } 971 972 dict.itabs = make([]itabInfo, r.Len()) 973 for i := range dict.itabs { 974 dict.itabs[i] = itabInfo{typ: r.typInfo(), iface: r.typInfo()} 975 } 976 977 return &dict 978 } 979 980 func (r *reader) typeParamNames() { 981 r.Sync(pkgbits.SyncTypeParamNames) 982 983 for range r.dict.targs[r.dict.implicits:] { 984 r.pos() 985 r.localIdent() 986 } 987 } 988 989 func (r *reader) method(rext *reader) *types.Field { 990 r.Sync(pkgbits.SyncMethod) 991 pos := r.pos() 992 pkg, sym := r.selector() 993 r.typeParamNames() 994 _, recv := r.param() 995 typ := r.signature(pkg, recv) 996 997 name := ir.NewNameAt(pos, ir.MethodSym(recv.Type, sym)) 998 setType(name, typ) 999 1000 name.Func = ir.NewFunc(r.pos()) 1001 name.Func.Nname = name 1002 1003 if r.hasTypeParams() { 1004 name.Func.SetDupok(true) 1005 if r.dict.shaped { 1006 typ = shapeSig(name.Func, r.dict) 1007 setType(name, typ) 1008 } 1009 } 1010 1011 rext.funcExt(name, sym) 1012 1013 meth := types.NewField(name.Func.Pos(), sym, typ) 1014 meth.Nname = name 1015 meth.SetNointerface(name.Func.Pragma&ir.Nointerface != 0) 1016 1017 return meth 1018 } 1019 1020 func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) { 1021 r.Sync(pkgbits.SyncSym) 1022 pkg = r.pkg() 1023 if name := r.String(); name != "" { 1024 sym = pkg.Lookup(name) 1025 } 1026 return 1027 } 1028 1029 func (r *reader) localIdent() (pkg *types.Pkg, sym *types.Sym) { 1030 r.Sync(pkgbits.SyncLocalIdent) 1031 pkg = r.pkg() 1032 if name := r.String(); name != "" { 1033 sym = pkg.Lookup(name) 1034 } 1035 return 1036 } 1037 1038 func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) { 1039 r.Sync(pkgbits.SyncSelector) 1040 origPkg = r.pkg() 1041 name := r.String() 1042 pkg := origPkg 1043 if types.IsExported(name) { 1044 pkg = types.LocalPkg 1045 } 1046 sym = pkg.Lookup(name) 1047 return 1048 } 1049 1050 func (r *reader) hasTypeParams() bool { 1051 return r.dict.hasTypeParams() 1052 } 1053 1054 func (dict *readerDict) hasTypeParams() bool { 1055 return dict != nil && len(dict.targs) != 0 1056 } 1057 1058 // @@@ Compiler extensions 1059 1060 func (r *reader) funcExt(name *ir.Name, method *types.Sym) { 1061 r.Sync(pkgbits.SyncFuncExt) 1062 1063 name.Class = 0 // so MarkFunc doesn't complain 1064 ir.MarkFunc(name) 1065 1066 fn := name.Func 1067 1068 // XXX: Workaround because linker doesn't know how to copy Pos. 1069 if !fn.Pos().IsKnown() { 1070 fn.SetPos(name.Pos()) 1071 } 1072 1073 // Normally, we only compile local functions, which saves redundant compilation work. 1074 // n.Defn is not nil for local functions, and is nil for imported function. But for 1075 // generic functions, we might have an instantiation that no other package has seen before. 1076 // So we need to be conservative and compile it again. 1077 // 1078 // That's why name.Defn is set here, so ir.VisitFuncsBottomUp can analyze function. 1079 // TODO(mdempsky,cuonglm): find a cleaner way to handle this. 1080 if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() { 1081 name.Defn = fn 1082 } 1083 1084 fn.Pragma = r.pragmaFlag() 1085 r.linkname(name) 1086 1087 typecheck.Func(fn) 1088 1089 if r.Bool() { 1090 assert(name.Defn == nil) 1091 1092 fn.ABI = obj.ABI(r.Uint64()) 1093 1094 // Escape analysis. 1095 for _, fs := range &types.RecvsParams { 1096 for _, f := range fs(name.Type()).FieldSlice() { 1097 f.Note = r.String() 1098 } 1099 } 1100 1101 if r.Bool() { 1102 fn.Inl = &ir.Inline{ 1103 Cost: int32(r.Len()), 1104 CanDelayResults: r.Bool(), 1105 } 1106 } 1107 } else { 1108 r.addBody(name.Func, method) 1109 } 1110 r.Sync(pkgbits.SyncEOF) 1111 } 1112 1113 func (r *reader) typeExt(name *ir.Name) { 1114 r.Sync(pkgbits.SyncTypeExt) 1115 1116 typ := name.Type() 1117 1118 if r.hasTypeParams() { 1119 // Set "RParams" (really type arguments here, not parameters) so 1120 // this type is treated as "fully instantiated". This ensures the 1121 // type descriptor is written out as DUPOK and method wrappers are 1122 // generated even for imported types. 1123 var targs []*types.Type 1124 targs = append(targs, r.dict.targs...) 1125 typ.SetRParams(targs) 1126 } 1127 1128 name.SetPragma(r.pragmaFlag()) 1129 1130 typecheck.SetBaseTypeIndex(typ, r.Int64(), r.Int64()) 1131 } 1132 1133 func (r *reader) varExt(name *ir.Name) { 1134 r.Sync(pkgbits.SyncVarExt) 1135 r.linkname(name) 1136 } 1137 1138 func (r *reader) linkname(name *ir.Name) { 1139 assert(name.Op() == ir.ONAME) 1140 r.Sync(pkgbits.SyncLinkname) 1141 1142 if idx := r.Int64(); idx >= 0 { 1143 lsym := name.Linksym() 1144 lsym.SymIdx = int32(idx) 1145 lsym.Set(obj.AttrIndexed, true) 1146 } else { 1147 name.Sym().Linkname = r.String() 1148 } 1149 } 1150 1151 func (r *reader) pragmaFlag() ir.PragmaFlag { 1152 r.Sync(pkgbits.SyncPragma) 1153 return ir.PragmaFlag(r.Int()) 1154 } 1155 1156 // @@@ Function bodies 1157 1158 // bodyReader tracks where the serialized IR for a local or imported, 1159 // generic function's body can be found. 1160 var bodyReader = map[*ir.Func]pkgReaderIndex{} 1161 1162 // importBodyReader tracks where the serialized IR for an imported, 1163 // static (i.e., non-generic) function body can be read. 1164 var importBodyReader = map[*types.Sym]pkgReaderIndex{} 1165 1166 // bodyReaderFor returns the pkgReaderIndex for reading fn's 1167 // serialized IR, and whether one was found. 1168 func bodyReaderFor(fn *ir.Func) (pri pkgReaderIndex, ok bool) { 1169 if fn.Nname.Defn != nil { 1170 pri, ok = bodyReader[fn] 1171 base.AssertfAt(ok, base.Pos, "must have bodyReader for %v", fn) // must always be available 1172 } else { 1173 pri, ok = importBodyReader[fn.Sym()] 1174 } 1175 return 1176 } 1177 1178 // todoDicts holds the list of dictionaries that still need their 1179 // runtime dictionary objects constructed. 1180 var todoDicts []func() 1181 1182 // todoBodies holds the list of function bodies that still need to be 1183 // constructed. 1184 var todoBodies []*ir.Func 1185 1186 // addBody reads a function body reference from the element bitstream, 1187 // and associates it with fn. 1188 func (r *reader) addBody(fn *ir.Func, method *types.Sym) { 1189 // addBody should only be called for local functions or imported 1190 // generic functions; see comment in funcExt. 1191 assert(fn.Nname.Defn != nil) 1192 1193 idx := r.Reloc(pkgbits.RelocBody) 1194 1195 pri := pkgReaderIndex{r.p, idx, r.dict, method, nil} 1196 bodyReader[fn] = pri 1197 1198 if r.curfn == nil { 1199 todoBodies = append(todoBodies, fn) 1200 return 1201 } 1202 1203 pri.funcBody(fn) 1204 } 1205 1206 func (pri pkgReaderIndex) funcBody(fn *ir.Func) { 1207 r := pri.asReader(pkgbits.RelocBody, pkgbits.SyncFuncBody) 1208 r.funcBody(fn) 1209 } 1210 1211 // funcBody reads a function body definition from the element 1212 // bitstream, and populates fn with it. 1213 func (r *reader) funcBody(fn *ir.Func) { 1214 r.curfn = fn 1215 r.closureVars = fn.ClosureVars 1216 if len(r.closureVars) != 0 && r.hasTypeParams() { 1217 r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit 1218 } 1219 1220 ir.WithFunc(fn, func() { 1221 r.funcargs(fn) 1222 1223 if r.syntheticBody(fn.Pos()) { 1224 return 1225 } 1226 1227 if !r.Bool() { 1228 return 1229 } 1230 1231 body := r.stmts() 1232 if body == nil { 1233 body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(src.NoXPos, nil))} 1234 } 1235 fn.Body = body 1236 fn.Endlineno = r.pos() 1237 }) 1238 1239 r.marker.WriteTo(fn) 1240 } 1241 1242 // syntheticBody adds a synthetic body to r.curfn if appropriate, and 1243 // reports whether it did. 1244 func (r *reader) syntheticBody(pos src.XPos) bool { 1245 if r.synthetic != nil { 1246 r.synthetic(pos, r) 1247 return true 1248 } 1249 1250 // If this function has type parameters and isn't shaped, then we 1251 // just tail call its corresponding shaped variant. 1252 if r.hasTypeParams() && !r.dict.shaped { 1253 r.callShaped(pos) 1254 return true 1255 } 1256 1257 return false 1258 } 1259 1260 // callShaped emits a tail call to r.shapedFn, passing along the 1261 // arguments to the current function. 1262 func (r *reader) callShaped(pos src.XPos) { 1263 shapedObj := r.dict.shapedObj 1264 assert(shapedObj != nil) 1265 1266 var shapedFn ir.Node 1267 if r.methodSym == nil { 1268 // Instantiating a generic function; shapedObj is the shaped 1269 // function itself. 1270 assert(shapedObj.Op() == ir.ONAME && shapedObj.Class == ir.PFUNC) 1271 shapedFn = shapedObj 1272 } else { 1273 // Instantiating a generic type's method; shapedObj is the shaped 1274 // type, so we need to select it's corresponding method. 1275 shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym) 1276 } 1277 1278 recvs, params := r.syntheticArgs(pos) 1279 1280 // Construct the arguments list: receiver (if any), then runtime 1281 // dictionary, and finally normal parameters. 1282 // 1283 // Note: For simplicity, shaped methods are added as normal methods 1284 // on their shaped types. So existing code (e.g., packages ir and 1285 // typecheck) expects the shaped type to appear as the receiver 1286 // parameter (or first parameter, as a method expression). Hence 1287 // putting the dictionary parameter after that is the least invasive 1288 // solution at the moment. 1289 var args ir.Nodes 1290 args.Append(recvs...) 1291 args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict)))) 1292 args.Append(params...) 1293 1294 r.syntheticTailCall(pos, shapedFn, args) 1295 } 1296 1297 // syntheticArgs returns the recvs and params arguments passed to the 1298 // current function. 1299 func (r *reader) syntheticArgs(pos src.XPos) (recvs, params ir.Nodes) { 1300 sig := r.curfn.Nname.Type() 1301 1302 inlVarIdx := 0 1303 addParams := func(out *ir.Nodes, params []*types.Field) { 1304 for _, param := range params { 1305 var arg ir.Node 1306 if param.Nname != nil { 1307 name := param.Nname.(*ir.Name) 1308 if !ir.IsBlank(name) { 1309 if r.inlCall != nil { 1310 // During inlining, we want the respective inlvar where we 1311 // assigned the callee's arguments. 1312 arg = r.inlvars[inlVarIdx] 1313 } else { 1314 // Otherwise, we can use the parameter itself directly. 1315 base.AssertfAt(name.Curfn == r.curfn, name.Pos(), "%v has curfn %v, but want %v", name, name.Curfn, r.curfn) 1316 arg = name 1317 } 1318 } 1319 } 1320 1321 // For anonymous and blank parameters, we don't have an *ir.Name 1322 // to use as the argument. However, since we know the shaped 1323 // function won't use the value either, we can just pass the 1324 // zero value. (Also unfortunately, we don't have an easy 1325 // zero-value IR node; so we use a default-initialized temporary 1326 // variable.) 1327 if arg == nil { 1328 tmp := typecheck.TempAt(pos, r.curfn, param.Type) 1329 r.curfn.Body.Append( 1330 typecheck.Stmt(ir.NewDecl(pos, ir.ODCL, tmp)), 1331 typecheck.Stmt(ir.NewAssignStmt(pos, tmp, nil)), 1332 ) 1333 arg = tmp 1334 } 1335 1336 out.Append(arg) 1337 inlVarIdx++ 1338 } 1339 } 1340 1341 addParams(&recvs, sig.Recvs().FieldSlice()) 1342 addParams(¶ms, sig.Params().FieldSlice()) 1343 return 1344 } 1345 1346 // syntheticTailCall emits a tail call to fn, passing the given 1347 // arguments list. 1348 func (r *reader) syntheticTailCall(pos src.XPos, fn ir.Node, args ir.Nodes) { 1349 // Mark the function as a wrapper so it doesn't show up in stack 1350 // traces. 1351 r.curfn.SetWrapper(true) 1352 1353 call := typecheck.Call(pos, fn, args, fn.Type().IsVariadic()).(*ir.CallExpr) 1354 1355 var stmt ir.Node 1356 if fn.Type().NumResults() != 0 { 1357 stmt = typecheck.Stmt(ir.NewReturnStmt(pos, []ir.Node{call})) 1358 } else { 1359 stmt = call 1360 } 1361 r.curfn.Body.Append(stmt) 1362 } 1363 1364 // dictNameOf returns the runtime dictionary corresponding to dict. 1365 func (pr *pkgReader) dictNameOf(dict *readerDict) *ir.Name { 1366 pos := base.AutogeneratedPos 1367 1368 // Check that we only instantiate runtime dictionaries with real types. 1369 base.AssertfAt(!dict.shaped, pos, "runtime dictionary of shaped object %v", dict.baseSym) 1370 1371 sym := dict.baseSym.Pkg.Lookup(objabi.GlobalDictPrefix + "." + dict.baseSym.Name) 1372 if sym.Def != nil { 1373 return sym.Def.(*ir.Name) 1374 } 1375 1376 name := ir.NewNameAt(pos, sym) 1377 name.Class = ir.PEXTERN 1378 sym.Def = name // break cycles with mutual subdictionaries 1379 1380 lsym := name.Linksym() 1381 ot := 0 1382 1383 assertOffset := func(section string, offset int) { 1384 base.AssertfAt(ot == offset*types.PtrSize, pos, "writing section %v at offset %v, but it should be at %v*%v", section, ot, offset, types.PtrSize) 1385 } 1386 1387 assertOffset("type param method exprs", dict.typeParamMethodExprsOffset()) 1388 for _, info := range dict.typeParamMethodExprs { 1389 typeParam := dict.targs[info.typeParamIdx] 1390 method := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(typeParam), info.method)).(*ir.SelectorExpr) 1391 assert(method.Op() == ir.OMETHEXPR) 1392 1393 rsym := method.FuncName().Linksym() 1394 assert(rsym.ABI() == obj.ABIInternal) // must be ABIInternal; see ir.OCFUNC in ssagen/ssa.go 1395 1396 ot = objw.SymPtr(lsym, ot, rsym, 0) 1397 } 1398 1399 assertOffset("subdictionaries", dict.subdictsOffset()) 1400 for _, info := range dict.subdicts { 1401 explicits := pr.typListIdx(info.explicits, dict) 1402 1403 // Careful: Due to subdictionary cycles, name may not be fully 1404 // initialized yet. 1405 name := pr.objDictName(info.idx, dict.targs, explicits) 1406 1407 ot = objw.SymPtr(lsym, ot, name.Linksym(), 0) 1408 } 1409 1410 assertOffset("rtypes", dict.rtypesOffset()) 1411 for _, info := range dict.rtypes { 1412 typ := pr.typIdx(info, dict, true) 1413 ot = objw.SymPtr(lsym, ot, reflectdata.TypeLinksym(typ), 0) 1414 1415 // TODO(mdempsky): Double check this. 1416 reflectdata.MarkTypeUsedInInterface(typ, lsym) 1417 } 1418 1419 // For each (typ, iface) pair, we write the *runtime.itab pointer 1420 // for the pair. For pairs that don't actually require an itab 1421 // (i.e., typ is an interface, or iface is an empty interface), we 1422 // write a nil pointer instead. This is wasteful, but rare in 1423 // practice (e.g., instantiating a type parameter with an interface 1424 // type). 1425 assertOffset("itabs", dict.itabsOffset()) 1426 for _, info := range dict.itabs { 1427 typ := pr.typIdx(info.typ, dict, true) 1428 iface := pr.typIdx(info.iface, dict, true) 1429 1430 if !typ.IsInterface() && iface.IsInterface() && !iface.IsEmptyInterface() { 1431 ot = objw.SymPtr(lsym, ot, reflectdata.ITabLsym(typ, iface), 0) 1432 } else { 1433 ot += types.PtrSize 1434 } 1435 1436 // TODO(mdempsky): Double check this. 1437 reflectdata.MarkTypeUsedInInterface(typ, lsym) 1438 reflectdata.MarkTypeUsedInInterface(iface, lsym) 1439 } 1440 1441 objw.Global(lsym, int32(ot), obj.DUPOK|obj.RODATA) 1442 1443 name.SetType(dict.varType()) 1444 name.SetTypecheck(1) 1445 1446 return name 1447 } 1448 1449 // typeParamMethodExprsOffset returns the offset of the runtime 1450 // dictionary's type parameter method expressions section, in words. 1451 func (dict *readerDict) typeParamMethodExprsOffset() int { 1452 return 0 1453 } 1454 1455 // subdictsOffset returns the offset of the runtime dictionary's 1456 // subdictionary section, in words. 1457 func (dict *readerDict) subdictsOffset() int { 1458 return dict.typeParamMethodExprsOffset() + len(dict.typeParamMethodExprs) 1459 } 1460 1461 // rtypesOffset returns the offset of the runtime dictionary's rtypes 1462 // section, in words. 1463 func (dict *readerDict) rtypesOffset() int { 1464 return dict.subdictsOffset() + len(dict.subdicts) 1465 } 1466 1467 // itabsOffset returns the offset of the runtime dictionary's itabs 1468 // section, in words. 1469 func (dict *readerDict) itabsOffset() int { 1470 return dict.rtypesOffset() + len(dict.rtypes) 1471 } 1472 1473 // numWords returns the total number of words that comprise dict's 1474 // runtime dictionary variable. 1475 func (dict *readerDict) numWords() int64 { 1476 return int64(dict.itabsOffset() + len(dict.itabs)) 1477 } 1478 1479 // varType returns the type of dict's runtime dictionary variable. 1480 func (dict *readerDict) varType() *types.Type { 1481 return types.NewArray(types.Types[types.TUINTPTR], dict.numWords()) 1482 } 1483 1484 func (r *reader) funcargs(fn *ir.Func) { 1485 sig := fn.Nname.Type() 1486 1487 if recv := sig.Recv(); recv != nil { 1488 r.funcarg(recv, recv.Sym, ir.PPARAM) 1489 } 1490 for _, param := range sig.Params().FieldSlice() { 1491 r.funcarg(param, param.Sym, ir.PPARAM) 1492 } 1493 1494 for i, param := range sig.Results().FieldSlice() { 1495 sym := types.OrigSym(param.Sym) 1496 1497 if sym == nil || sym.IsBlank() { 1498 prefix := "~r" 1499 if r.inlCall != nil { 1500 prefix = "~R" 1501 } else if sym != nil { 1502 prefix = "~b" 1503 } 1504 sym = typecheck.LookupNum(prefix, i) 1505 } 1506 1507 r.funcarg(param, sym, ir.PPARAMOUT) 1508 } 1509 } 1510 1511 func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) { 1512 if sym == nil { 1513 assert(ctxt == ir.PPARAM) 1514 if r.inlCall != nil { 1515 r.inlvars.Append(ir.BlankNode) 1516 } 1517 return 1518 } 1519 1520 name := ir.NewNameAt(r.inlPos(param.Pos), sym) 1521 setType(name, param.Type) 1522 r.addLocal(name, ctxt) 1523 1524 if r.inlCall == nil { 1525 if !r.funarghack { 1526 param.Sym = sym 1527 param.Nname = name 1528 } 1529 } else { 1530 if ctxt == ir.PPARAMOUT { 1531 r.retvars.Append(name) 1532 } else { 1533 r.inlvars.Append(name) 1534 } 1535 } 1536 } 1537 1538 func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) { 1539 assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT) 1540 1541 if name.Sym().Name == dictParamName { 1542 r.dictParam = name 1543 } else { 1544 if r.synthetic == nil { 1545 r.Sync(pkgbits.SyncAddLocal) 1546 if r.p.SyncMarkers() { 1547 want := r.Int() 1548 if have := len(r.locals); have != want { 1549 base.FatalfAt(name.Pos(), "locals table has desynced") 1550 } 1551 } 1552 r.varDictIndex(name) 1553 } 1554 1555 r.locals = append(r.locals, name) 1556 } 1557 1558 name.SetUsed(true) 1559 1560 // TODO(mdempsky): Move earlier. 1561 if ir.IsBlank(name) { 1562 return 1563 } 1564 1565 if r.inlCall != nil { 1566 if ctxt == ir.PAUTO { 1567 name.SetInlLocal(true) 1568 } else { 1569 name.SetInlFormal(true) 1570 ctxt = ir.PAUTO 1571 } 1572 1573 // TODO(mdempsky): Rethink this hack. 1574 if strings.HasPrefix(name.Sym().Name, "~") || base.Flag.GenDwarfInl == 0 { 1575 name.SetPos(r.inlCall.Pos()) 1576 name.SetInlFormal(false) 1577 name.SetInlLocal(false) 1578 } 1579 } 1580 1581 name.Class = ctxt 1582 name.Curfn = r.curfn 1583 1584 r.curfn.Dcl = append(r.curfn.Dcl, name) 1585 1586 if ctxt == ir.PAUTO { 1587 name.SetFrameOffset(0) 1588 } 1589 } 1590 1591 func (r *reader) useLocal() *ir.Name { 1592 r.Sync(pkgbits.SyncUseObjLocal) 1593 if r.Bool() { 1594 return r.locals[r.Len()] 1595 } 1596 return r.closureVars[r.Len()] 1597 } 1598 1599 func (r *reader) openScope() { 1600 r.Sync(pkgbits.SyncOpenScope) 1601 pos := r.pos() 1602 1603 if base.Flag.Dwarf { 1604 r.scopeVars = append(r.scopeVars, len(r.curfn.Dcl)) 1605 r.marker.Push(pos) 1606 } 1607 } 1608 1609 func (r *reader) closeScope() { 1610 r.Sync(pkgbits.SyncCloseScope) 1611 r.lastCloseScopePos = r.pos() 1612 1613 r.closeAnotherScope() 1614 } 1615 1616 // closeAnotherScope is like closeScope, but it reuses the same mark 1617 // position as the last closeScope call. This is useful for "for" and 1618 // "if" statements, as their implicit blocks always end at the same 1619 // position as an explicit block. 1620 func (r *reader) closeAnotherScope() { 1621 r.Sync(pkgbits.SyncCloseAnotherScope) 1622 1623 if base.Flag.Dwarf { 1624 scopeVars := r.scopeVars[len(r.scopeVars)-1] 1625 r.scopeVars = r.scopeVars[:len(r.scopeVars)-1] 1626 1627 // Quirkish: noder decides which scopes to keep before 1628 // typechecking, whereas incremental typechecking during IR 1629 // construction can result in new autotemps being allocated. To 1630 // produce identical output, we ignore autotemps here for the 1631 // purpose of deciding whether to retract the scope. 1632 // 1633 // This is important for net/http/fcgi, because it contains: 1634 // 1635 // var body io.ReadCloser 1636 // if len(content) > 0 { 1637 // body, req.pw = io.Pipe() 1638 // } else { … } 1639 // 1640 // Notably, io.Pipe is inlinable, and inlining it introduces a ~R0 1641 // variable at the call site. 1642 // 1643 // Noder does not preserve the scope where the io.Pipe() call 1644 // resides, because it doesn't contain any declared variables in 1645 // source. So the ~R0 variable ends up being assigned to the 1646 // enclosing scope instead. 1647 // 1648 // However, typechecking this assignment also introduces 1649 // autotemps, because io.Pipe's results need conversion before 1650 // they can be assigned to their respective destination variables. 1651 // 1652 // TODO(mdempsky): We should probably just keep all scopes, and 1653 // let dwarfgen take care of pruning them instead. 1654 retract := true 1655 for _, n := range r.curfn.Dcl[scopeVars:] { 1656 if !n.AutoTemp() { 1657 retract = false 1658 break 1659 } 1660 } 1661 1662 if retract { 1663 // no variables were declared in this scope, so we can retract it. 1664 r.marker.Unpush() 1665 } else { 1666 r.marker.Pop(r.lastCloseScopePos) 1667 } 1668 } 1669 } 1670 1671 // @@@ Statements 1672 1673 func (r *reader) stmt() ir.Node { 1674 switch stmts := r.stmts(); len(stmts) { 1675 case 0: 1676 return nil 1677 case 1: 1678 return stmts[0] 1679 default: 1680 return ir.NewBlockStmt(stmts[0].Pos(), stmts) 1681 } 1682 } 1683 1684 func (r *reader) stmts() []ir.Node { 1685 assert(ir.CurFunc == r.curfn) 1686 var res ir.Nodes 1687 1688 r.Sync(pkgbits.SyncStmts) 1689 for { 1690 tag := codeStmt(r.Code(pkgbits.SyncStmt1)) 1691 if tag == stmtEnd { 1692 r.Sync(pkgbits.SyncStmtsEnd) 1693 return res 1694 } 1695 1696 if n := r.stmt1(tag, &res); n != nil { 1697 res.Append(typecheck.Stmt(n)) 1698 } 1699 } 1700 } 1701 1702 func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node { 1703 var label *types.Sym 1704 if n := len(*out); n > 0 { 1705 if ls, ok := (*out)[n-1].(*ir.LabelStmt); ok { 1706 label = ls.Label 1707 } 1708 } 1709 1710 switch tag { 1711 default: 1712 panic("unexpected statement") 1713 1714 case stmtAssign: 1715 pos := r.pos() 1716 names, lhs := r.assignList() 1717 rhs := r.multiExpr() 1718 1719 if len(rhs) == 0 { 1720 for _, name := range names { 1721 as := ir.NewAssignStmt(pos, name, nil) 1722 as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name)) 1723 out.Append(typecheck.Stmt(as)) 1724 } 1725 return nil 1726 } 1727 1728 if len(lhs) == 1 && len(rhs) == 1 { 1729 n := ir.NewAssignStmt(pos, lhs[0], rhs[0]) 1730 n.Def = r.initDefn(n, names) 1731 return n 1732 } 1733 1734 n := ir.NewAssignListStmt(pos, ir.OAS2, lhs, rhs) 1735 n.Def = r.initDefn(n, names) 1736 return n 1737 1738 case stmtAssignOp: 1739 op := r.op() 1740 lhs := r.expr() 1741 pos := r.pos() 1742 rhs := r.expr() 1743 return ir.NewAssignOpStmt(pos, op, lhs, rhs) 1744 1745 case stmtIncDec: 1746 op := r.op() 1747 lhs := r.expr() 1748 pos := r.pos() 1749 n := ir.NewAssignOpStmt(pos, op, lhs, ir.NewBasicLit(pos, one)) 1750 n.IncDec = true 1751 return n 1752 1753 case stmtBlock: 1754 out.Append(r.blockStmt()...) 1755 return nil 1756 1757 case stmtBranch: 1758 pos := r.pos() 1759 op := r.op() 1760 sym := r.optLabel() 1761 return ir.NewBranchStmt(pos, op, sym) 1762 1763 case stmtCall: 1764 pos := r.pos() 1765 op := r.op() 1766 call := r.expr() 1767 return ir.NewGoDeferStmt(pos, op, call) 1768 1769 case stmtExpr: 1770 return r.expr() 1771 1772 case stmtFor: 1773 return r.forStmt(label) 1774 1775 case stmtIf: 1776 return r.ifStmt() 1777 1778 case stmtLabel: 1779 pos := r.pos() 1780 sym := r.label() 1781 return ir.NewLabelStmt(pos, sym) 1782 1783 case stmtReturn: 1784 pos := r.pos() 1785 results := r.multiExpr() 1786 return ir.NewReturnStmt(pos, results) 1787 1788 case stmtSelect: 1789 return r.selectStmt(label) 1790 1791 case stmtSend: 1792 pos := r.pos() 1793 ch := r.expr() 1794 value := r.expr() 1795 return ir.NewSendStmt(pos, ch, value) 1796 1797 case stmtSwitch: 1798 return r.switchStmt(label) 1799 } 1800 } 1801 1802 func (r *reader) assignList() ([]*ir.Name, []ir.Node) { 1803 lhs := make([]ir.Node, r.Len()) 1804 var names []*ir.Name 1805 1806 for i := range lhs { 1807 expr, def := r.assign() 1808 lhs[i] = expr 1809 if def { 1810 names = append(names, expr.(*ir.Name)) 1811 } 1812 } 1813 1814 return names, lhs 1815 } 1816 1817 // assign returns an assignee expression. It also reports whether the 1818 // returned expression is a newly declared variable. 1819 func (r *reader) assign() (ir.Node, bool) { 1820 switch tag := codeAssign(r.Code(pkgbits.SyncAssign)); tag { 1821 default: 1822 panic("unhandled assignee expression") 1823 1824 case assignBlank: 1825 return typecheck.AssignExpr(ir.BlankNode), false 1826 1827 case assignDef: 1828 pos := r.pos() 1829 setBasePos(pos) 1830 _, sym := r.localIdent() 1831 typ := r.typ() 1832 1833 name := ir.NewNameAt(pos, sym) 1834 setType(name, typ) 1835 r.addLocal(name, ir.PAUTO) 1836 return name, true 1837 1838 case assignExpr: 1839 return r.expr(), false 1840 } 1841 } 1842 1843 func (r *reader) blockStmt() []ir.Node { 1844 r.Sync(pkgbits.SyncBlockStmt) 1845 r.openScope() 1846 stmts := r.stmts() 1847 r.closeScope() 1848 return stmts 1849 } 1850 1851 func (r *reader) forStmt(label *types.Sym) ir.Node { 1852 r.Sync(pkgbits.SyncForStmt) 1853 1854 r.openScope() 1855 1856 if r.Bool() { 1857 pos := r.pos() 1858 rang := ir.NewRangeStmt(pos, nil, nil, nil, nil) 1859 rang.Label = label 1860 1861 names, lhs := r.assignList() 1862 if len(lhs) >= 1 { 1863 rang.Key = lhs[0] 1864 if len(lhs) >= 2 { 1865 rang.Value = lhs[1] 1866 } 1867 } 1868 rang.Def = r.initDefn(rang, names) 1869 1870 rang.X = r.expr() 1871 if rang.X.Type().IsMap() { 1872 rang.RType = r.rtype(pos) 1873 } 1874 if rang.Key != nil && !ir.IsBlank(rang.Key) { 1875 rang.KeyTypeWord, rang.KeySrcRType = r.convRTTI(pos) 1876 } 1877 if rang.Value != nil && !ir.IsBlank(rang.Value) { 1878 rang.ValueTypeWord, rang.ValueSrcRType = r.convRTTI(pos) 1879 } 1880 1881 rang.Body = r.blockStmt() 1882 r.closeAnotherScope() 1883 1884 return rang 1885 } 1886 1887 pos := r.pos() 1888 init := r.stmt() 1889 cond := r.optExpr() 1890 post := r.stmt() 1891 body := r.blockStmt() 1892 r.closeAnotherScope() 1893 1894 stmt := ir.NewForStmt(pos, init, cond, post, body) 1895 stmt.Label = label 1896 return stmt 1897 } 1898 1899 func (r *reader) ifStmt() ir.Node { 1900 r.Sync(pkgbits.SyncIfStmt) 1901 r.openScope() 1902 pos := r.pos() 1903 init := r.stmts() 1904 cond := r.expr() 1905 then := r.blockStmt() 1906 els := r.stmts() 1907 n := ir.NewIfStmt(pos, cond, then, els) 1908 n.SetInit(init) 1909 r.closeAnotherScope() 1910 return n 1911 } 1912 1913 func (r *reader) selectStmt(label *types.Sym) ir.Node { 1914 r.Sync(pkgbits.SyncSelectStmt) 1915 1916 pos := r.pos() 1917 clauses := make([]*ir.CommClause, r.Len()) 1918 for i := range clauses { 1919 if i > 0 { 1920 r.closeScope() 1921 } 1922 r.openScope() 1923 1924 pos := r.pos() 1925 comm := r.stmt() 1926 body := r.stmts() 1927 1928 // "case i = <-c: ..." may require an implicit conversion (e.g., 1929 // see fixedbugs/bug312.go). Currently, typecheck throws away the 1930 // implicit conversion and relies on it being reinserted later, 1931 // but that would lose any explicit RTTI operands too. To preserve 1932 // RTTI, we rewrite this as "case tmp := <-c: i = tmp; ...". 1933 if as, ok := comm.(*ir.AssignStmt); ok && as.Op() == ir.OAS && !as.Def { 1934 if conv, ok := as.Y.(*ir.ConvExpr); ok && conv.Op() == ir.OCONVIFACE { 1935 base.AssertfAt(conv.Implicit(), conv.Pos(), "expected implicit conversion: %v", conv) 1936 1937 recv := conv.X 1938 base.AssertfAt(recv.Op() == ir.ORECV, recv.Pos(), "expected receive expression: %v", recv) 1939 1940 tmp := r.temp(pos, recv.Type()) 1941 1942 // Replace comm with `tmp := <-c`. 1943 tmpAs := ir.NewAssignStmt(pos, tmp, recv) 1944 tmpAs.Def = true 1945 tmpAs.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp)) 1946 comm = tmpAs 1947 1948 // Change original assignment to `i = tmp`, and prepend to body. 1949 conv.X = tmp 1950 body = append([]ir.Node{as}, body...) 1951 } 1952 } 1953 1954 // multiExpr will have desugared a comma-ok receive expression 1955 // into a separate statement. However, the rest of the compiler 1956 // expects comm to be the OAS2RECV statement itself, so we need to 1957 // shuffle things around to fit that pattern. 1958 if as2, ok := comm.(*ir.AssignListStmt); ok && as2.Op() == ir.OAS2 { 1959 init := ir.TakeInit(as2.Rhs[0]) 1960 base.AssertfAt(len(init) == 1 && init[0].Op() == ir.OAS2RECV, as2.Pos(), "unexpected assignment: %+v", as2) 1961 1962 comm = init[0] 1963 body = append([]ir.Node{as2}, body...) 1964 } 1965 1966 clauses[i] = ir.NewCommStmt(pos, comm, body) 1967 } 1968 if len(clauses) > 0 { 1969 r.closeScope() 1970 } 1971 n := ir.NewSelectStmt(pos, clauses) 1972 n.Label = label 1973 return n 1974 } 1975 1976 func (r *reader) switchStmt(label *types.Sym) ir.Node { 1977 r.Sync(pkgbits.SyncSwitchStmt) 1978 1979 r.openScope() 1980 pos := r.pos() 1981 init := r.stmt() 1982 1983 var tag ir.Node 1984 var ident *ir.Ident 1985 var iface *types.Type 1986 if r.Bool() { 1987 pos := r.pos() 1988 if r.Bool() { 1989 pos := r.pos() 1990 _, sym := r.localIdent() 1991 ident = ir.NewIdent(pos, sym) 1992 } 1993 x := r.expr() 1994 iface = x.Type() 1995 tag = ir.NewTypeSwitchGuard(pos, ident, x) 1996 } else { 1997 tag = r.optExpr() 1998 } 1999 2000 clauses := make([]*ir.CaseClause, r.Len()) 2001 for i := range clauses { 2002 if i > 0 { 2003 r.closeScope() 2004 } 2005 r.openScope() 2006 2007 pos := r.pos() 2008 var cases, rtypes []ir.Node 2009 if iface != nil { 2010 cases = make([]ir.Node, r.Len()) 2011 if len(cases) == 0 { 2012 cases = nil // TODO(mdempsky): Unclear if this matters. 2013 } 2014 for i := range cases { 2015 if r.Bool() { // case nil 2016 cases[i] = typecheck.Expr(types.BuiltinPkg.Lookup("nil").Def.(*ir.NilExpr)) 2017 } else { 2018 cases[i] = r.exprType() 2019 } 2020 } 2021 } else { 2022 cases = r.exprList() 2023 2024 // For `switch { case any(true): }` (e.g., issue 3980 in 2025 // test/switch.go), the backend still creates a mixed bool/any 2026 // comparison, and we need to explicitly supply the RTTI for the 2027 // comparison. 2028 // 2029 // TODO(mdempsky): Change writer.go to desugar "switch {" into 2030 // "switch true {", which we already handle correctly. 2031 if tag == nil { 2032 for i, cas := range cases { 2033 if cas.Type().IsEmptyInterface() { 2034 for len(rtypes) < i { 2035 rtypes = append(rtypes, nil) 2036 } 2037 rtypes = append(rtypes, reflectdata.TypePtrAt(cas.Pos(), types.Types[types.TBOOL])) 2038 } 2039 } 2040 } 2041 } 2042 2043 clause := ir.NewCaseStmt(pos, cases, nil) 2044 clause.RTypes = rtypes 2045 2046 if ident != nil { 2047 pos := r.pos() 2048 typ := r.typ() 2049 2050 name := ir.NewNameAt(pos, ident.Sym()) 2051 setType(name, typ) 2052 r.addLocal(name, ir.PAUTO) 2053 clause.Var = name 2054 name.Defn = tag 2055 } 2056 2057 clause.Body = r.stmts() 2058 clauses[i] = clause 2059 } 2060 if len(clauses) > 0 { 2061 r.closeScope() 2062 } 2063 r.closeScope() 2064 2065 n := ir.NewSwitchStmt(pos, tag, clauses) 2066 n.Label = label 2067 if init != nil { 2068 n.SetInit([]ir.Node{init}) 2069 } 2070 return n 2071 } 2072 2073 func (r *reader) label() *types.Sym { 2074 r.Sync(pkgbits.SyncLabel) 2075 name := r.String() 2076 if r.inlCall != nil { 2077 name = fmt.Sprintf("~%s·%d", name, inlgen) 2078 } 2079 return typecheck.Lookup(name) 2080 } 2081 2082 func (r *reader) optLabel() *types.Sym { 2083 r.Sync(pkgbits.SyncOptLabel) 2084 if r.Bool() { 2085 return r.label() 2086 } 2087 return nil 2088 } 2089 2090 // initDefn marks the given names as declared by defn and populates 2091 // its Init field with ODCL nodes. It then reports whether any names 2092 // were so declared, which can be used to initialize defn.Def. 2093 func (r *reader) initDefn(defn ir.InitNode, names []*ir.Name) bool { 2094 if len(names) == 0 { 2095 return false 2096 } 2097 2098 init := make([]ir.Node, len(names)) 2099 for i, name := range names { 2100 name.Defn = defn 2101 init[i] = ir.NewDecl(name.Pos(), ir.ODCL, name) 2102 } 2103 defn.SetInit(init) 2104 return true 2105 } 2106 2107 // @@@ Expressions 2108 2109 // expr reads and returns a typechecked expression. 2110 func (r *reader) expr() (res ir.Node) { 2111 defer func() { 2112 if res != nil && res.Typecheck() == 0 { 2113 base.FatalfAt(res.Pos(), "%v missed typecheck", res) 2114 } 2115 }() 2116 2117 switch tag := codeExpr(r.Code(pkgbits.SyncExpr)); tag { 2118 default: 2119 panic("unhandled expression") 2120 2121 case exprLocal: 2122 return typecheck.Expr(r.useLocal()) 2123 2124 case exprGlobal: 2125 // Callee instead of Expr allows builtins 2126 // TODO(mdempsky): Handle builtins directly in exprCall, like method calls? 2127 return typecheck.Callee(r.obj()) 2128 2129 case exprFuncInst: 2130 origPos, pos := r.origPos() 2131 wrapperFn, baseFn, dictPtr := r.funcInst(pos) 2132 if wrapperFn != nil { 2133 return wrapperFn 2134 } 2135 return r.curry(origPos, false, baseFn, dictPtr, nil) 2136 2137 case exprConst: 2138 pos := r.pos() 2139 typ := r.typ() 2140 val := FixValue(typ, r.Value()) 2141 op := r.op() 2142 orig := r.String() 2143 return typecheck.Expr(OrigConst(pos, typ, val, op, orig)) 2144 2145 case exprNil: 2146 pos := r.pos() 2147 typ := r.typ() 2148 return Nil(pos, typ) 2149 2150 case exprCompLit: 2151 return r.compLit() 2152 2153 case exprFuncLit: 2154 return r.funcLit() 2155 2156 case exprFieldVal: 2157 x := r.expr() 2158 pos := r.pos() 2159 _, sym := r.selector() 2160 2161 return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr) 2162 2163 case exprMethodVal: 2164 recv := r.expr() 2165 origPos, pos := r.origPos() 2166 wrapperFn, baseFn, dictPtr := r.methodExpr() 2167 2168 // For simple wrapperFn values, the existing machinery for creating 2169 // and deduplicating wrapperFn value wrappers still works fine. 2170 if wrapperFn, ok := wrapperFn.(*ir.SelectorExpr); ok && wrapperFn.Op() == ir.OMETHEXPR { 2171 // The receiver expression we constructed may have a shape type. 2172 // For example, in fixedbugs/issue54343.go, `New[int]()` is 2173 // constructed as `New[go.shape.int](&.dict.New[int])`, which 2174 // has type `*T[go.shape.int]`, not `*T[int]`. 2175 // 2176 // However, the method we want to select here is `(*T[int]).M`, 2177 // not `(*T[go.shape.int]).M`, so we need to manually convert 2178 // the type back so that the OXDOT resolves correctly. 2179 // 2180 // TODO(mdempsky): Logically it might make more sense for 2181 // exprCall to take responsibility for setting a non-shaped 2182 // result type, but this is the only place where we care 2183 // currently. And only because existing ir.OMETHVALUE backend 2184 // code relies on n.X.Type() instead of n.Selection.Recv().Type 2185 // (because the latter is types.FakeRecvType() in the case of 2186 // interface method values). 2187 // 2188 if recv.Type().HasShape() { 2189 typ := wrapperFn.Type().Params().Field(0).Type 2190 if !types.Identical(typ, recv.Type()) { 2191 base.FatalfAt(wrapperFn.Pos(), "receiver %L does not match %L", recv, wrapperFn) 2192 } 2193 recv = typecheck.Expr(ir.NewConvExpr(recv.Pos(), ir.OCONVNOP, typ, recv)) 2194 } 2195 2196 n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, recv, wrapperFn.Sel)).(*ir.SelectorExpr) 2197 2198 // As a consistency check here, we make sure "n" selected the 2199 // same method (represented by a types.Field) that wrapperFn 2200 // selected. However, for anonymous receiver types, there can be 2201 // multiple such types.Field instances (#58563). So we may need 2202 // to fallback to making sure Sym and Type (including the 2203 // receiver parameter's type) match. 2204 if n.Selection != wrapperFn.Selection { 2205 assert(n.Selection.Sym == wrapperFn.Selection.Sym) 2206 assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type)) 2207 assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type)) 2208 } 2209 2210 wrapper := methodValueWrapper{ 2211 rcvr: n.X.Type(), 2212 method: n.Selection, 2213 } 2214 2215 if r.importedDef() { 2216 haveMethodValueWrappers = append(haveMethodValueWrappers, wrapper) 2217 } else { 2218 needMethodValueWrappers = append(needMethodValueWrappers, wrapper) 2219 } 2220 return n 2221 } 2222 2223 // For more complicated method expressions, we construct a 2224 // function literal wrapper. 2225 return r.curry(origPos, true, baseFn, recv, dictPtr) 2226 2227 case exprMethodExpr: 2228 recv := r.typ() 2229 2230 implicits := make([]int, r.Len()) 2231 for i := range implicits { 2232 implicits[i] = r.Len() 2233 } 2234 var deref, addr bool 2235 if r.Bool() { 2236 deref = true 2237 } else if r.Bool() { 2238 addr = true 2239 } 2240 2241 origPos, pos := r.origPos() 2242 wrapperFn, baseFn, dictPtr := r.methodExpr() 2243 2244 // If we already have a wrapper and don't need to do anything with 2245 // it, we can just return the wrapper directly. 2246 // 2247 // N.B., we use implicits/deref/addr here as the source of truth 2248 // rather than types.Identical, because the latter can be confused 2249 // by tricky promoted methods (e.g., typeparam/mdempsky/21.go). 2250 if wrapperFn != nil && len(implicits) == 0 && !deref && !addr { 2251 if !types.Identical(recv, wrapperFn.Type().Params().Field(0).Type) { 2252 base.FatalfAt(pos, "want receiver type %v, but have method %L", recv, wrapperFn) 2253 } 2254 return wrapperFn 2255 } 2256 2257 // Otherwise, if the wrapper function is a static method 2258 // expression (OMETHEXPR) and the receiver type is unshaped, then 2259 // we can rely on a statically generated wrapper being available. 2260 if method, ok := wrapperFn.(*ir.SelectorExpr); ok && method.Op() == ir.OMETHEXPR && !recv.HasShape() { 2261 return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), method.Sel)).(*ir.SelectorExpr) 2262 } 2263 2264 return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr) 2265 2266 case exprIndex: 2267 x := r.expr() 2268 pos := r.pos() 2269 index := r.expr() 2270 n := typecheck.Expr(ir.NewIndexExpr(pos, x, index)) 2271 switch n.Op() { 2272 case ir.OINDEXMAP: 2273 n := n.(*ir.IndexExpr) 2274 n.RType = r.rtype(pos) 2275 } 2276 return n 2277 2278 case exprSlice: 2279 x := r.expr() 2280 pos := r.pos() 2281 var index [3]ir.Node 2282 for i := range index { 2283 index[i] = r.optExpr() 2284 } 2285 op := ir.OSLICE 2286 if index[2] != nil { 2287 op = ir.OSLICE3 2288 } 2289 return typecheck.Expr(ir.NewSliceExpr(pos, op, x, index[0], index[1], index[2])) 2290 2291 case exprAssert: 2292 x := r.expr() 2293 pos := r.pos() 2294 typ := r.exprType() 2295 srcRType := r.rtype(pos) 2296 2297 // TODO(mdempsky): Always emit ODYNAMICDOTTYPE for uniformity? 2298 if typ, ok := typ.(*ir.DynamicType); ok && typ.Op() == ir.ODYNAMICTYPE { 2299 assert := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.RType) 2300 assert.SrcRType = srcRType 2301 assert.ITab = typ.ITab 2302 return typed(typ.Type(), assert) 2303 } 2304 return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ.Type())) 2305 2306 case exprUnaryOp: 2307 op := r.op() 2308 pos := r.pos() 2309 x := r.expr() 2310 2311 switch op { 2312 case ir.OADDR: 2313 return typecheck.Expr(typecheck.NodAddrAt(pos, x)) 2314 case ir.ODEREF: 2315 return typecheck.Expr(ir.NewStarExpr(pos, x)) 2316 } 2317 return typecheck.Expr(ir.NewUnaryExpr(pos, op, x)) 2318 2319 case exprBinaryOp: 2320 op := r.op() 2321 x := r.expr() 2322 pos := r.pos() 2323 y := r.expr() 2324 2325 switch op { 2326 case ir.OANDAND, ir.OOROR: 2327 return typecheck.Expr(ir.NewLogicalExpr(pos, op, x, y)) 2328 } 2329 return typecheck.Expr(ir.NewBinaryExpr(pos, op, x, y)) 2330 2331 case exprRecv: 2332 x := r.expr() 2333 pos := r.pos() 2334 for i, n := 0, r.Len(); i < n; i++ { 2335 x = Implicit(DotField(pos, x, r.Len())) 2336 } 2337 if r.Bool() { // needs deref 2338 x = Implicit(Deref(pos, x.Type().Elem(), x)) 2339 } else if r.Bool() { // needs addr 2340 x = Implicit(Addr(pos, x)) 2341 } 2342 return x 2343 2344 case exprCall: 2345 var fun ir.Node 2346 var args ir.Nodes 2347 if r.Bool() { // method call 2348 recv := r.expr() 2349 _, method, dictPtr := r.methodExpr() 2350 2351 if recv.Type().IsInterface() && method.Op() == ir.OMETHEXPR { 2352 method := method.(*ir.SelectorExpr) 2353 2354 // The compiler backend (e.g., devirtualization) handle 2355 // OCALLINTER/ODOTINTER better than OCALLFUNC/OMETHEXPR for 2356 // interface calls, so we prefer to continue constructing 2357 // calls that way where possible. 2358 // 2359 // There are also corner cases where semantically it's perhaps 2360 // significant; e.g., fixedbugs/issue15975.go, #38634, #52025. 2361 2362 fun = typecheck.Callee(ir.NewSelectorExpr(method.Pos(), ir.OXDOT, recv, method.Sel)) 2363 } else { 2364 if recv.Type().IsInterface() { 2365 // N.B., this happens currently for typeparam/issue51521.go 2366 // and typeparam/typeswitch3.go. 2367 if base.Flag.LowerM > 0 { 2368 base.WarnfAt(method.Pos(), "imprecise interface call") 2369 } 2370 } 2371 2372 fun = method 2373 args.Append(recv) 2374 } 2375 if dictPtr != nil { 2376 args.Append(dictPtr) 2377 } 2378 } else if r.Bool() { // call to instanced function 2379 pos := r.pos() 2380 _, shapedFn, dictPtr := r.funcInst(pos) 2381 fun = shapedFn 2382 args.Append(dictPtr) 2383 } else { 2384 fun = r.expr() 2385 } 2386 pos := r.pos() 2387 args.Append(r.multiExpr()...) 2388 dots := r.Bool() 2389 n := typecheck.Call(pos, fun, args, dots) 2390 switch n.Op() { 2391 case ir.OAPPEND: 2392 n := n.(*ir.CallExpr) 2393 n.RType = r.rtype(pos) 2394 // For append(a, b...), we don't need the implicit conversion. The typechecker already 2395 // ensured that a and b are both slices with the same base type, or []byte and string. 2396 if n.IsDDD { 2397 if conv, ok := n.Args[1].(*ir.ConvExpr); ok && conv.Op() == ir.OCONVNOP && conv.Implicit() { 2398 n.Args[1] = conv.X 2399 } 2400 } 2401 case ir.OCOPY: 2402 n := n.(*ir.BinaryExpr) 2403 n.RType = r.rtype(pos) 2404 case ir.ODELETE: 2405 n := n.(*ir.CallExpr) 2406 n.RType = r.rtype(pos) 2407 case ir.OUNSAFESLICE: 2408 n := n.(*ir.BinaryExpr) 2409 n.RType = r.rtype(pos) 2410 } 2411 return n 2412 2413 case exprMake: 2414 pos := r.pos() 2415 typ := r.exprType() 2416 extra := r.exprs() 2417 n := typecheck.Expr(ir.NewCallExpr(pos, ir.OMAKE, nil, append([]ir.Node{typ}, extra...))).(*ir.MakeExpr) 2418 n.RType = r.rtype(pos) 2419 return n 2420 2421 case exprNew: 2422 pos := r.pos() 2423 typ := r.exprType() 2424 return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, typ)) 2425 2426 case exprReshape: 2427 typ := r.typ() 2428 x := r.expr() 2429 2430 if types.IdenticalStrict(x.Type(), typ) { 2431 return x 2432 } 2433 2434 // Comparison expressions are constructed as "untyped bool" still. 2435 // 2436 // TODO(mdempsky): It should be safe to reshape them here too, but 2437 // maybe it's better to construct them with the proper type 2438 // instead. 2439 if x.Type() == types.UntypedBool && typ.IsBoolean() { 2440 return x 2441 } 2442 2443 base.AssertfAt(x.Type().HasShape() || typ.HasShape(), x.Pos(), "%L and %v are not shape types", x, typ) 2444 base.AssertfAt(types.Identical(x.Type(), typ), x.Pos(), "%L is not shape-identical to %v", x, typ) 2445 2446 // We use ir.HasUniquePos here as a check that x only appears once 2447 // in the AST, so it's okay for us to call SetType without 2448 // breaking any other uses of it. 2449 // 2450 // Notably, any ONAMEs should already have the exactly right shape 2451 // type and been caught by types.IdenticalStrict above. 2452 base.AssertfAt(ir.HasUniquePos(x), x.Pos(), "cannot call SetType(%v) on %L", typ, x) 2453 2454 if base.Debug.Reshape != 0 { 2455 base.WarnfAt(x.Pos(), "reshaping %L to %v", x, typ) 2456 } 2457 2458 x.SetType(typ) 2459 return x 2460 2461 case exprConvert: 2462 implicit := r.Bool() 2463 typ := r.typ() 2464 pos := r.pos() 2465 typeWord, srcRType := r.convRTTI(pos) 2466 dstTypeParam := r.Bool() 2467 identical := r.Bool() 2468 x := r.expr() 2469 2470 // TODO(mdempsky): Stop constructing expressions of untyped type. 2471 x = typecheck.DefaultLit(x, typ) 2472 2473 ce := ir.NewConvExpr(pos, ir.OCONV, typ, x) 2474 ce.TypeWord, ce.SrcRType = typeWord, srcRType 2475 if implicit { 2476 ce.SetImplicit(true) 2477 } 2478 n := typecheck.Expr(ce) 2479 2480 // Conversions between non-identical, non-empty interfaces always 2481 // requires a runtime call, even if they have identical underlying 2482 // interfaces. This is because we create separate itab instances 2483 // for each unique interface type, not merely each unique 2484 // interface shape. 2485 // 2486 // However, due to shape types, typecheck.Expr might mistakenly 2487 // think a conversion between two non-empty interfaces are 2488 // identical and set ir.OCONVNOP, instead of ir.OCONVIFACE. To 2489 // ensure we update the itab field appropriately, we force it to 2490 // ir.OCONVIFACE instead when shape types are involved. 2491 // 2492 // TODO(mdempsky): Are there other places we might get this wrong? 2493 // Should this be moved down into typecheck.{Assign,Convert}op? 2494 // This would be a non-issue if itabs were unique for each 2495 // *underlying* interface type instead. 2496 if !identical { 2497 if n, ok := n.(*ir.ConvExpr); ok && n.Op() == ir.OCONVNOP && n.Type().IsInterface() && !n.Type().IsEmptyInterface() && (n.Type().HasShape() || n.X.Type().HasShape()) { 2498 n.SetOp(ir.OCONVIFACE) 2499 } 2500 } 2501 2502 // spec: "If the type is a type parameter, the constant is converted 2503 // into a non-constant value of the type parameter." 2504 if dstTypeParam && ir.IsConstNode(n) { 2505 // Wrap in an OCONVNOP node to ensure result is non-constant. 2506 n = Implicit(ir.NewConvExpr(pos, ir.OCONVNOP, n.Type(), n)) 2507 n.SetTypecheck(1) 2508 } 2509 return n 2510 } 2511 } 2512 2513 // funcInst reads an instantiated function reference, and returns 2514 // three (possibly nil) expressions related to it: 2515 // 2516 // baseFn is always non-nil: it's either a function of the appropriate 2517 // type already, or it has an extra dictionary parameter as the first 2518 // parameter. 2519 // 2520 // If dictPtr is non-nil, then it's a dictionary argument that must be 2521 // passed as the first argument to baseFn. 2522 // 2523 // If wrapperFn is non-nil, then it's either the same as baseFn (if 2524 // dictPtr is nil), or it's semantically equivalent to currying baseFn 2525 // to pass dictPtr. (wrapperFn is nil when dictPtr is an expression 2526 // that needs to be computed dynamically.) 2527 // 2528 // For callers that are creating a call to the returned function, it's 2529 // best to emit a call to baseFn, and include dictPtr in the arguments 2530 // list as appropriate. 2531 // 2532 // For callers that want to return the function without invoking it, 2533 // they may return wrapperFn if it's non-nil; but otherwise, they need 2534 // to create their own wrapper. 2535 func (r *reader) funcInst(pos src.XPos) (wrapperFn, baseFn, dictPtr ir.Node) { 2536 // Like in methodExpr, I'm pretty sure this isn't needed. 2537 var implicits []*types.Type 2538 if r.dict != nil { 2539 implicits = r.dict.targs 2540 } 2541 2542 if r.Bool() { // dynamic subdictionary 2543 idx := r.Len() 2544 info := r.dict.subdicts[idx] 2545 explicits := r.p.typListIdx(info.explicits, r.dict) 2546 2547 baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) 2548 2549 // TODO(mdempsky): Is there a more robust way to get the 2550 // dictionary pointer type here? 2551 dictPtrType := baseFn.Type().Params().Field(0).Type 2552 dictPtr = typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, dictPtrType, r.dictWord(pos, r.dict.subdictsOffset()+idx))) 2553 2554 return 2555 } 2556 2557 info := r.objInfo() 2558 explicits := r.p.typListIdx(info.explicits, r.dict) 2559 2560 wrapperFn = r.p.objIdx(info.idx, implicits, explicits, false).(*ir.Name) 2561 baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) 2562 2563 dictName := r.p.objDictName(info.idx, implicits, explicits) 2564 dictPtr = typecheck.Expr(ir.NewAddrExpr(pos, dictName)) 2565 2566 return 2567 } 2568 2569 func (pr *pkgReader) objDictName(idx pkgbits.Index, implicits, explicits []*types.Type) *ir.Name { 2570 rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) 2571 _, sym := rname.qualifiedIdent() 2572 tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) 2573 2574 if tag == pkgbits.ObjStub { 2575 assert(!sym.IsBlank()) 2576 if pri, ok := objReader[sym]; ok { 2577 return pri.pr.objDictName(pri.idx, nil, explicits) 2578 } 2579 base.Fatalf("unresolved stub: %v", sym) 2580 } 2581 2582 dict := pr.objDictIdx(sym, idx, implicits, explicits, false) 2583 2584 return pr.dictNameOf(dict) 2585 } 2586 2587 // curry returns a function literal that calls fun with arg0 and 2588 // (optionally) arg1, accepting additional arguments to the function 2589 // literal as necessary to satisfy fun's signature. 2590 // 2591 // If nilCheck is true and arg0 is an interface value, then it's 2592 // checked to be non-nil as an initial step at the point of evaluating 2593 // the function literal itself. 2594 func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node { 2595 var captured ir.Nodes 2596 captured.Append(fun, arg0) 2597 if arg1 != nil { 2598 captured.Append(arg1) 2599 } 2600 2601 params, results := syntheticSig(fun.Type()) 2602 params = params[len(captured)-1:] // skip curried parameters 2603 typ := types.NewSignature(types.NoPkg, nil, nil, params, results) 2604 2605 addBody := func(pos src.XPos, r *reader, captured []ir.Node) { 2606 recvs, params := r.syntheticArgs(pos) 2607 assert(len(recvs) == 0) 2608 2609 fun := captured[0] 2610 2611 var args ir.Nodes 2612 args.Append(captured[1:]...) 2613 args.Append(params...) 2614 2615 r.syntheticTailCall(pos, fun, args) 2616 } 2617 2618 return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody) 2619 } 2620 2621 // methodExprWrap returns a function literal that changes method's 2622 // first parameter's type to recv, and uses implicits/deref/addr to 2623 // select the appropriate receiver parameter to pass to method. 2624 func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node { 2625 var captured ir.Nodes 2626 captured.Append(method) 2627 2628 params, results := syntheticSig(method.Type()) 2629 2630 // Change first parameter to recv. 2631 params[0].Type = recv 2632 2633 // If we have a dictionary pointer argument to pass, then omit the 2634 // underlying method expression's dictionary parameter from the 2635 // returned signature too. 2636 if dictPtr != nil { 2637 captured.Append(dictPtr) 2638 params = append(params[:1], params[2:]...) 2639 } 2640 2641 typ := types.NewSignature(types.NoPkg, nil, nil, params, results) 2642 2643 addBody := func(pos src.XPos, r *reader, captured []ir.Node) { 2644 recvs, args := r.syntheticArgs(pos) 2645 assert(len(recvs) == 0) 2646 2647 fn := captured[0] 2648 2649 // Rewrite first argument based on implicits/deref/addr. 2650 { 2651 arg := args[0] 2652 for _, ix := range implicits { 2653 arg = Implicit(DotField(pos, arg, ix)) 2654 } 2655 if deref { 2656 arg = Implicit(Deref(pos, arg.Type().Elem(), arg)) 2657 } else if addr { 2658 arg = Implicit(Addr(pos, arg)) 2659 } 2660 args[0] = arg 2661 } 2662 2663 // Insert dictionary argument, if provided. 2664 if dictPtr != nil { 2665 newArgs := make([]ir.Node, len(args)+1) 2666 newArgs[0] = args[0] 2667 newArgs[1] = captured[1] 2668 copy(newArgs[2:], args[1:]) 2669 args = newArgs 2670 } 2671 2672 r.syntheticTailCall(pos, fn, args) 2673 } 2674 2675 return r.syntheticClosure(origPos, typ, false, captured, addBody) 2676 } 2677 2678 // syntheticClosure constructs a synthetic function literal for 2679 // currying dictionary arguments. origPos is the position used for the 2680 // closure, which must be a non-inlined position. typ is the function 2681 // literal's signature type. 2682 // 2683 // captures is a list of expressions that need to be evaluated at the 2684 // point of function literal evaluation and captured by the function 2685 // literal. If ifaceHack is true and captures[1] is an interface type, 2686 // it's checked to be non-nil after evaluation. 2687 // 2688 // addBody is a callback function to populate the function body. The 2689 // list of captured values passed back has the captured variables for 2690 // use within the function literal, corresponding to the expressions 2691 // in captures. 2692 func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node { 2693 // isSafe reports whether n is an expression that we can safely 2694 // defer to evaluating inside the closure instead, to avoid storing 2695 // them into the closure. 2696 // 2697 // In practice this is always (and only) the wrappee function. 2698 isSafe := func(n ir.Node) bool { 2699 if n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PFUNC { 2700 return true 2701 } 2702 if n.Op() == ir.OMETHEXPR { 2703 return true 2704 } 2705 2706 return false 2707 } 2708 2709 // The ODCLFUNC and its body need to use the original position, but 2710 // the OCLOSURE node and any Init statements should use the inlined 2711 // position instead. See also the explanation in reader.funcLit. 2712 inlPos := r.inlPos(origPos) 2713 2714 fn := ir.NewClosureFunc(origPos, r.curfn != nil) 2715 fn.SetWrapper(true) 2716 clo := fn.OClosure 2717 clo.SetPos(inlPos) 2718 ir.NameClosure(clo, r.curfn) 2719 2720 setType(fn.Nname, typ) 2721 typecheck.Func(fn) 2722 setType(clo, fn.Type()) 2723 2724 var init ir.Nodes 2725 for i, n := range captures { 2726 if isSafe(n) { 2727 continue // skip capture; can reference directly 2728 } 2729 2730 tmp := r.tempCopy(inlPos, n, &init) 2731 ir.NewClosureVar(origPos, fn, tmp) 2732 2733 // We need to nil check interface receivers at the point of method 2734 // value evaluation, ugh. 2735 if ifaceHack && i == 1 && n.Type().IsInterface() { 2736 check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp)) 2737 init.Append(typecheck.Stmt(check)) 2738 } 2739 } 2740 2741 pri := pkgReaderIndex{synthetic: func(pos src.XPos, r *reader) { 2742 captured := make([]ir.Node, len(captures)) 2743 next := 0 2744 for i, n := range captures { 2745 if isSafe(n) { 2746 captured[i] = n 2747 } else { 2748 captured[i] = r.closureVars[next] 2749 next++ 2750 } 2751 } 2752 assert(next == len(r.closureVars)) 2753 2754 addBody(origPos, r, captured) 2755 }} 2756 bodyReader[fn] = pri 2757 pri.funcBody(fn) 2758 2759 // TODO(mdempsky): Remove hard-coding of typecheck.Target. 2760 return ir.InitExpr(init, ir.UseClosure(clo, typecheck.Target)) 2761 } 2762 2763 // syntheticSig duplicates and returns the params and results lists 2764 // for sig, but renaming anonymous parameters so they can be assigned 2765 // ir.Names. 2766 func syntheticSig(sig *types.Type) (params, results []*types.Field) { 2767 clone := func(params []*types.Field) []*types.Field { 2768 res := make([]*types.Field, len(params)) 2769 for i, param := range params { 2770 sym := param.Sym 2771 if sym == nil || sym.Name == "_" { 2772 sym = typecheck.LookupNum(".anon", i) 2773 } 2774 // TODO(mdempsky): It would be nice to preserve the original 2775 // parameter positions here instead, but at least 2776 // typecheck.NewMethodType replaces them with base.Pos, making 2777 // them useless. Worse, the positions copied from base.Pos may 2778 // have inlining contexts, which we definitely don't want here 2779 // (e.g., #54625). 2780 res[i] = types.NewField(base.AutogeneratedPos, sym, param.Type) 2781 res[i].SetIsDDD(param.IsDDD()) 2782 } 2783 return res 2784 } 2785 2786 return clone(sig.Params().FieldSlice()), clone(sig.Results().FieldSlice()) 2787 } 2788 2789 func (r *reader) optExpr() ir.Node { 2790 if r.Bool() { 2791 return r.expr() 2792 } 2793 return nil 2794 } 2795 2796 // methodExpr reads a method expression reference, and returns three 2797 // (possibly nil) expressions related to it: 2798 // 2799 // baseFn is always non-nil: it's either a function of the appropriate 2800 // type already, or it has an extra dictionary parameter as the second 2801 // parameter (i.e., immediately after the promoted receiver 2802 // parameter). 2803 // 2804 // If dictPtr is non-nil, then it's a dictionary argument that must be 2805 // passed as the second argument to baseFn. 2806 // 2807 // If wrapperFn is non-nil, then it's either the same as baseFn (if 2808 // dictPtr is nil), or it's semantically equivalent to currying baseFn 2809 // to pass dictPtr. (wrapperFn is nil when dictPtr is an expression 2810 // that needs to be computed dynamically.) 2811 // 2812 // For callers that are creating a call to the returned method, it's 2813 // best to emit a call to baseFn, and include dictPtr in the arguments 2814 // list as appropriate. 2815 // 2816 // For callers that want to return a method expression without 2817 // invoking it, they may return wrapperFn if it's non-nil; but 2818 // otherwise, they need to create their own wrapper. 2819 func (r *reader) methodExpr() (wrapperFn, baseFn, dictPtr ir.Node) { 2820 recv := r.typ() 2821 sig0 := r.typ() 2822 pos := r.pos() 2823 _, sym := r.selector() 2824 2825 // Signature type to return (i.e., recv prepended to the method's 2826 // normal parameters list). 2827 sig := typecheck.NewMethodType(sig0, recv) 2828 2829 if r.Bool() { // type parameter method expression 2830 idx := r.Len() 2831 word := r.dictWord(pos, r.dict.typeParamMethodExprsOffset()+idx) 2832 2833 // TODO(mdempsky): If the type parameter was instantiated with an 2834 // interface type (i.e., embed.IsInterface()), then we could 2835 // return the OMETHEXPR instead and save an indirection. 2836 2837 // We wrote the method expression's entry point PC into the 2838 // dictionary, but for Go `func` values we need to return a 2839 // closure (i.e., pointer to a structure with the PC as the first 2840 // field). Because method expressions don't have any closure 2841 // variables, we pun the dictionary entry as the closure struct. 2842 fn := typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, sig, ir.NewAddrExpr(pos, word))) 2843 return fn, fn, nil 2844 } 2845 2846 // TODO(mdempsky): I'm pretty sure this isn't needed: implicits is 2847 // only relevant to locally defined types, but they can't have 2848 // (non-promoted) methods. 2849 var implicits []*types.Type 2850 if r.dict != nil { 2851 implicits = r.dict.targs 2852 } 2853 2854 if r.Bool() { // dynamic subdictionary 2855 idx := r.Len() 2856 info := r.dict.subdicts[idx] 2857 explicits := r.p.typListIdx(info.explicits, r.dict) 2858 2859 shapedObj := r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) 2860 shapedFn := shapedMethodExpr(pos, shapedObj, sym) 2861 2862 // TODO(mdempsky): Is there a more robust way to get the 2863 // dictionary pointer type here? 2864 dictPtrType := shapedFn.Type().Params().Field(1).Type 2865 dictPtr := typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, dictPtrType, r.dictWord(pos, r.dict.subdictsOffset()+idx))) 2866 2867 return nil, shapedFn, dictPtr 2868 } 2869 2870 if r.Bool() { // static dictionary 2871 info := r.objInfo() 2872 explicits := r.p.typListIdx(info.explicits, r.dict) 2873 2874 shapedObj := r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) 2875 shapedFn := shapedMethodExpr(pos, shapedObj, sym) 2876 2877 dict := r.p.objDictName(info.idx, implicits, explicits) 2878 dictPtr := typecheck.Expr(ir.NewAddrExpr(pos, dict)) 2879 2880 // Check that dictPtr matches shapedFn's dictionary parameter. 2881 if !types.Identical(dictPtr.Type(), shapedFn.Type().Params().Field(1).Type) { 2882 base.FatalfAt(pos, "dict %L, but shaped method %L", dict, shapedFn) 2883 } 2884 2885 // For statically known instantiations, we can take advantage of 2886 // the stenciled wrapper. 2887 base.AssertfAt(!recv.HasShape(), pos, "shaped receiver %v", recv) 2888 wrapperFn := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), sym)).(*ir.SelectorExpr) 2889 base.AssertfAt(types.Identical(sig, wrapperFn.Type()), pos, "wrapper %L does not have type %v", wrapperFn, sig) 2890 2891 return wrapperFn, shapedFn, dictPtr 2892 } 2893 2894 // Simple method expression; no dictionary needed. 2895 base.AssertfAt(!recv.HasShape() || recv.IsInterface(), pos, "shaped receiver %v", recv) 2896 fn := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), sym)).(*ir.SelectorExpr) 2897 return fn, fn, nil 2898 } 2899 2900 // shapedMethodExpr returns the specified method on the given shaped 2901 // type. 2902 func shapedMethodExpr(pos src.XPos, obj *ir.Name, sym *types.Sym) *ir.SelectorExpr { 2903 assert(obj.Op() == ir.OTYPE) 2904 2905 typ := obj.Type() 2906 assert(typ.HasShape()) 2907 2908 method := func() *types.Field { 2909 for _, method := range typ.Methods().Slice() { 2910 if method.Sym == sym { 2911 return method 2912 } 2913 } 2914 2915 base.FatalfAt(pos, "failed to find method %v in shaped type %v", sym, typ) 2916 panic("unreachable") 2917 }() 2918 2919 // Construct an OMETHEXPR node. 2920 recv := method.Type.Recv().Type 2921 return typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, ir.TypeNode(recv), sym)).(*ir.SelectorExpr) 2922 } 2923 2924 func (r *reader) multiExpr() []ir.Node { 2925 r.Sync(pkgbits.SyncMultiExpr) 2926 2927 if r.Bool() { // N:1 2928 pos := r.pos() 2929 expr := r.expr() 2930 2931 results := make([]ir.Node, r.Len()) 2932 as := ir.NewAssignListStmt(pos, ir.OAS2, nil, []ir.Node{expr}) 2933 as.Def = true 2934 for i := range results { 2935 tmp := r.temp(pos, r.typ()) 2936 as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp)) 2937 as.Lhs.Append(tmp) 2938 2939 res := ir.Node(tmp) 2940 if r.Bool() { 2941 n := ir.NewConvExpr(pos, ir.OCONV, r.typ(), res) 2942 n.TypeWord, n.SrcRType = r.convRTTI(pos) 2943 n.SetImplicit(true) 2944 res = typecheck.Expr(n) 2945 } 2946 results[i] = res 2947 } 2948 2949 // TODO(mdempsky): Could use ir.InlinedCallExpr instead? 2950 results[0] = ir.InitExpr([]ir.Node{typecheck.Stmt(as)}, results[0]) 2951 return results 2952 } 2953 2954 // N:N 2955 exprs := make([]ir.Node, r.Len()) 2956 if len(exprs) == 0 { 2957 return nil 2958 } 2959 for i := range exprs { 2960 exprs[i] = r.expr() 2961 } 2962 return exprs 2963 } 2964 2965 // temp returns a new autotemp of the specified type. 2966 func (r *reader) temp(pos src.XPos, typ *types.Type) *ir.Name { 2967 // See typecheck.typecheckargs. 2968 curfn := r.curfn 2969 if curfn == nil { 2970 curfn = typecheck.InitTodoFunc 2971 } 2972 2973 return typecheck.TempAt(pos, curfn, typ) 2974 } 2975 2976 // tempCopy declares and returns a new autotemp initialized to the 2977 // value of expr. 2978 func (r *reader) tempCopy(pos src.XPos, expr ir.Node, init *ir.Nodes) *ir.Name { 2979 if r.curfn == nil { 2980 // Escape analysis doesn't know how to handle package-scope 2981 // function literals with free variables (i.e., that capture 2982 // temporary variables added to typecheck.InitTodoFunc). 2983 // 2984 // stencil.go works around this limitation by spilling values to 2985 // global variables instead, but that causes the value to stay 2986 // alive indefinitely; see go.dev/issue/54343. 2987 // 2988 // This code path (which implements the same workaround) isn't 2989 // actually needed by unified IR, because it creates uses normal 2990 // OMETHEXPR/OMETHVALUE nodes when statically-known instantiated 2991 // types are used. But it's kept around for now because it's handy 2992 // for testing that the generic fallback paths work correctly. 2993 base.Fatalf("tempCopy called at package scope") 2994 2995 tmp := staticinit.StaticName(expr.Type()) 2996 2997 assign := ir.NewAssignStmt(pos, tmp, expr) 2998 assign.Def = true 2999 tmp.Defn = assign 3000 3001 typecheck.Target.Decls = append(typecheck.Target.Decls, typecheck.Stmt(assign)) 3002 3003 return tmp 3004 } 3005 3006 tmp := r.temp(pos, expr.Type()) 3007 3008 init.Append(typecheck.Stmt(ir.NewDecl(pos, ir.ODCL, tmp))) 3009 3010 assign := ir.NewAssignStmt(pos, tmp, expr) 3011 assign.Def = true 3012 init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, tmp, expr))) 3013 3014 tmp.Defn = assign 3015 3016 return tmp 3017 } 3018 3019 func (r *reader) compLit() ir.Node { 3020 r.Sync(pkgbits.SyncCompLit) 3021 pos := r.pos() 3022 typ0 := r.typ() 3023 3024 typ := typ0 3025 if typ.IsPtr() { 3026 typ = typ.Elem() 3027 } 3028 if typ.Kind() == types.TFORW { 3029 base.FatalfAt(pos, "unresolved composite literal type: %v", typ) 3030 } 3031 var rtype ir.Node 3032 if typ.IsMap() { 3033 rtype = r.rtype(pos) 3034 } 3035 isStruct := typ.Kind() == types.TSTRUCT 3036 3037 elems := make([]ir.Node, r.Len()) 3038 for i := range elems { 3039 elemp := &elems[i] 3040 3041 if isStruct { 3042 sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil) 3043 *elemp, elemp = sk, &sk.Value 3044 } else if r.Bool() { 3045 kv := ir.NewKeyExpr(r.pos(), r.expr(), nil) 3046 *elemp, elemp = kv, &kv.Value 3047 } 3048 3049 *elemp = wrapName(r.pos(), r.expr()) 3050 } 3051 3052 lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, elems)) 3053 if rtype != nil { 3054 lit := lit.(*ir.CompLitExpr) 3055 lit.RType = rtype 3056 } 3057 if typ0.IsPtr() { 3058 lit = typecheck.Expr(typecheck.NodAddrAt(pos, lit)) 3059 lit.SetType(typ0) 3060 } 3061 return lit 3062 } 3063 3064 func wrapName(pos src.XPos, x ir.Node) ir.Node { 3065 // These nodes do not carry line numbers. 3066 // Introduce a wrapper node to give them the correct line. 3067 switch ir.Orig(x).Op() { 3068 case ir.OTYPE, ir.OLITERAL: 3069 if x.Sym() == nil { 3070 break 3071 } 3072 fallthrough 3073 case ir.ONAME, ir.ONONAME, ir.ONIL: 3074 p := ir.NewParenExpr(pos, x) 3075 p.SetImplicit(true) 3076 return p 3077 } 3078 return x 3079 } 3080 3081 func (r *reader) funcLit() ir.Node { 3082 r.Sync(pkgbits.SyncFuncLit) 3083 3084 // The underlying function declaration (including its parameters' 3085 // positions, if any) need to remain the original, uninlined 3086 // positions. This is because we track inlining-context on nodes so 3087 // we can synthesize the extra implied stack frames dynamically when 3088 // generating tracebacks, whereas those stack frames don't make 3089 // sense *within* the function literal. (Any necessary inlining 3090 // adjustments will have been applied to the call expression 3091 // instead.) 3092 // 3093 // This is subtle, and getting it wrong leads to cycles in the 3094 // inlining tree, which lead to infinite loops during stack 3095 // unwinding (#46234, #54625). 3096 // 3097 // Note that we *do* want the inline-adjusted position for the 3098 // OCLOSURE node, because that position represents where any heap 3099 // allocation of the closure is credited (#49171). 3100 r.suppressInlPos++ 3101 pos := r.pos() 3102 xtype2 := r.signature(types.LocalPkg, nil) 3103 r.suppressInlPos-- 3104 3105 fn := ir.NewClosureFunc(pos, r.curfn != nil) 3106 clo := fn.OClosure 3107 clo.SetPos(r.inlPos(pos)) // see comment above 3108 ir.NameClosure(clo, r.curfn) 3109 3110 setType(fn.Nname, xtype2) 3111 typecheck.Func(fn) 3112 setType(clo, fn.Type()) 3113 3114 fn.ClosureVars = make([]*ir.Name, 0, r.Len()) 3115 for len(fn.ClosureVars) < cap(fn.ClosureVars) { 3116 ir.NewClosureVar(r.pos(), fn, r.useLocal()) 3117 } 3118 if param := r.dictParam; param != nil { 3119 // If we have a dictionary parameter, capture it too. For 3120 // simplicity, we capture it last and unconditionally. 3121 ir.NewClosureVar(param.Pos(), fn, param) 3122 } 3123 3124 r.addBody(fn, nil) 3125 3126 // TODO(mdempsky): Remove hard-coding of typecheck.Target. 3127 return ir.UseClosure(clo, typecheck.Target) 3128 } 3129 3130 func (r *reader) exprList() []ir.Node { 3131 r.Sync(pkgbits.SyncExprList) 3132 return r.exprs() 3133 } 3134 3135 func (r *reader) exprs() []ir.Node { 3136 r.Sync(pkgbits.SyncExprs) 3137 nodes := make([]ir.Node, r.Len()) 3138 if len(nodes) == 0 { 3139 return nil // TODO(mdempsky): Unclear if this matters. 3140 } 3141 for i := range nodes { 3142 nodes[i] = r.expr() 3143 } 3144 return nodes 3145 } 3146 3147 // dictWord returns an expression to return the specified 3148 // uintptr-typed word from the dictionary parameter. 3149 func (r *reader) dictWord(pos src.XPos, idx int) ir.Node { 3150 base.AssertfAt(r.dictParam != nil, pos, "expected dictParam in %v", r.curfn) 3151 return typecheck.Expr(ir.NewIndexExpr(pos, r.dictParam, ir.NewBasicLit(pos, constant.MakeInt64(int64(idx))))) 3152 } 3153 3154 // rttiWord is like dictWord, but converts it to *byte (the type used 3155 // internally to represent *runtime._type and *runtime.itab). 3156 func (r *reader) rttiWord(pos src.XPos, idx int) ir.Node { 3157 return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, types.NewPtr(types.Types[types.TUINT8]), r.dictWord(pos, idx))) 3158 } 3159 3160 // rtype reads a type reference from the element bitstream, and 3161 // returns an expression of type *runtime._type representing that 3162 // type. 3163 func (r *reader) rtype(pos src.XPos) ir.Node { 3164 _, rtype := r.rtype0(pos) 3165 return rtype 3166 } 3167 3168 func (r *reader) rtype0(pos src.XPos) (typ *types.Type, rtype ir.Node) { 3169 r.Sync(pkgbits.SyncRType) 3170 if r.Bool() { // derived type 3171 idx := r.Len() 3172 info := r.dict.rtypes[idx] 3173 typ = r.p.typIdx(info, r.dict, true) 3174 rtype = r.rttiWord(pos, r.dict.rtypesOffset()+idx) 3175 return 3176 } 3177 3178 typ = r.typ() 3179 rtype = reflectdata.TypePtrAt(pos, typ) 3180 return 3181 } 3182 3183 // varDictIndex populates name.DictIndex if name is a derived type. 3184 func (r *reader) varDictIndex(name *ir.Name) { 3185 if r.Bool() { 3186 idx := 1 + r.dict.rtypesOffset() + r.Len() 3187 if int(uint16(idx)) != idx { 3188 base.FatalfAt(name.Pos(), "DictIndex overflow for %v: %v", name, idx) 3189 } 3190 name.DictIndex = uint16(idx) 3191 } 3192 } 3193 3194 // itab returns a (typ, iface) pair of types. 3195 // 3196 // typRType and ifaceRType are expressions that evaluate to the 3197 // *runtime._type for typ and iface, respectively. 3198 // 3199 // If typ is a concrete type and iface is a non-empty interface type, 3200 // then itab is an expression that evaluates to the *runtime.itab for 3201 // the pair. Otherwise, itab is nil. 3202 func (r *reader) itab(pos src.XPos) (typ *types.Type, typRType ir.Node, iface *types.Type, ifaceRType ir.Node, itab ir.Node) { 3203 typ, typRType = r.rtype0(pos) 3204 iface, ifaceRType = r.rtype0(pos) 3205 3206 idx := -1 3207 if r.Bool() { 3208 idx = r.Len() 3209 } 3210 3211 if !typ.IsInterface() && iface.IsInterface() && !iface.IsEmptyInterface() { 3212 if idx >= 0 { 3213 itab = r.rttiWord(pos, r.dict.itabsOffset()+idx) 3214 } else { 3215 base.AssertfAt(!typ.HasShape(), pos, "%v is a shape type", typ) 3216 base.AssertfAt(!iface.HasShape(), pos, "%v is a shape type", iface) 3217 3218 lsym := reflectdata.ITabLsym(typ, iface) 3219 itab = typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8]) 3220 } 3221 } 3222 3223 return 3224 } 3225 3226 // convRTTI returns expressions appropriate for populating an 3227 // ir.ConvExpr's TypeWord and SrcRType fields, respectively. 3228 func (r *reader) convRTTI(pos src.XPos) (typeWord, srcRType ir.Node) { 3229 r.Sync(pkgbits.SyncConvRTTI) 3230 src, srcRType0, dst, dstRType, itab := r.itab(pos) 3231 if !dst.IsInterface() { 3232 return 3233 } 3234 3235 // See reflectdata.ConvIfaceTypeWord. 3236 switch { 3237 case dst.IsEmptyInterface(): 3238 if !src.IsInterface() { 3239 typeWord = srcRType0 // direct eface construction 3240 } 3241 case !src.IsInterface(): 3242 typeWord = itab // direct iface construction 3243 default: 3244 typeWord = dstRType // convI2I 3245 } 3246 3247 // See reflectdata.ConvIfaceSrcRType. 3248 if !src.IsInterface() { 3249 srcRType = srcRType0 3250 } 3251 3252 return 3253 } 3254 3255 func (r *reader) exprType() ir.Node { 3256 r.Sync(pkgbits.SyncExprType) 3257 pos := r.pos() 3258 3259 var typ *types.Type 3260 var rtype, itab ir.Node 3261 3262 if r.Bool() { 3263 typ, rtype, _, _, itab = r.itab(pos) 3264 if !typ.IsInterface() { 3265 rtype = nil // TODO(mdempsky): Leave set? 3266 } 3267 } else { 3268 typ, rtype = r.rtype0(pos) 3269 3270 if !r.Bool() { // not derived 3271 // TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node. 3272 n := ir.TypeNode(typ) 3273 n.SetTypecheck(1) 3274 return n 3275 } 3276 } 3277 3278 dt := ir.NewDynamicType(pos, rtype) 3279 dt.ITab = itab 3280 return typed(typ, dt) 3281 } 3282 3283 func (r *reader) op() ir.Op { 3284 r.Sync(pkgbits.SyncOp) 3285 return ir.Op(r.Len()) 3286 } 3287 3288 // @@@ Package initialization 3289 3290 func (r *reader) pkgInit(self *types.Pkg, target *ir.Package) { 3291 cgoPragmas := make([][]string, r.Len()) 3292 for i := range cgoPragmas { 3293 cgoPragmas[i] = r.Strings() 3294 } 3295 target.CgoPragmas = cgoPragmas 3296 3297 r.pkgDecls(target) 3298 3299 r.Sync(pkgbits.SyncEOF) 3300 } 3301 3302 func (r *reader) pkgDecls(target *ir.Package) { 3303 r.Sync(pkgbits.SyncDecls) 3304 for { 3305 switch code := codeDecl(r.Code(pkgbits.SyncDecl)); code { 3306 default: 3307 panic(fmt.Sprintf("unhandled decl: %v", code)) 3308 3309 case declEnd: 3310 return 3311 3312 case declFunc: 3313 names := r.pkgObjs(target) 3314 assert(len(names) == 1) 3315 target.Decls = append(target.Decls, names[0].Func) 3316 3317 case declMethod: 3318 typ := r.typ() 3319 _, sym := r.selector() 3320 3321 method := typecheck.Lookdot1(nil, sym, typ, typ.Methods(), 0) 3322 target.Decls = append(target.Decls, method.Nname.(*ir.Name).Func) 3323 3324 case declVar: 3325 pos := r.pos() 3326 names := r.pkgObjs(target) 3327 values := r.exprList() 3328 3329 if len(names) > 1 && len(values) == 1 { 3330 as := ir.NewAssignListStmt(pos, ir.OAS2, nil, values) 3331 for _, name := range names { 3332 as.Lhs.Append(name) 3333 name.Defn = as 3334 } 3335 target.Decls = append(target.Decls, as) 3336 } else { 3337 for i, name := range names { 3338 as := ir.NewAssignStmt(pos, name, nil) 3339 if i < len(values) { 3340 as.Y = values[i] 3341 } 3342 name.Defn = as 3343 target.Decls = append(target.Decls, as) 3344 } 3345 } 3346 3347 if n := r.Len(); n > 0 { 3348 assert(len(names) == 1) 3349 embeds := make([]ir.Embed, n) 3350 for i := range embeds { 3351 embeds[i] = ir.Embed{Pos: r.pos(), Patterns: r.Strings()} 3352 } 3353 names[0].Embed = &embeds 3354 target.Embeds = append(target.Embeds, names[0]) 3355 } 3356 3357 case declOther: 3358 r.pkgObjs(target) 3359 } 3360 } 3361 } 3362 3363 func (r *reader) pkgObjs(target *ir.Package) []*ir.Name { 3364 r.Sync(pkgbits.SyncDeclNames) 3365 nodes := make([]*ir.Name, r.Len()) 3366 for i := range nodes { 3367 r.Sync(pkgbits.SyncDeclName) 3368 3369 name := r.obj().(*ir.Name) 3370 nodes[i] = name 3371 3372 sym := name.Sym() 3373 if sym.IsBlank() { 3374 continue 3375 } 3376 3377 switch name.Class { 3378 default: 3379 base.FatalfAt(name.Pos(), "unexpected class: %v", name.Class) 3380 3381 case ir.PEXTERN: 3382 target.Externs = append(target.Externs, name) 3383 3384 case ir.PFUNC: 3385 assert(name.Type().Recv() == nil) 3386 3387 // TODO(mdempsky): Cleaner way to recognize init? 3388 if strings.HasPrefix(sym.Name, "init.") { 3389 target.Inits = append(target.Inits, name.Func) 3390 } 3391 } 3392 3393 if types.IsExported(sym.Name) { 3394 assert(!sym.OnExportList()) 3395 target.Exports = append(target.Exports, name) 3396 sym.SetOnExportList(true) 3397 } 3398 3399 if base.Flag.AsmHdr != "" { 3400 assert(!sym.Asm()) 3401 target.Asms = append(target.Asms, name) 3402 sym.SetAsm(true) 3403 } 3404 } 3405 3406 return nodes 3407 } 3408 3409 // @@@ Inlining 3410 3411 // unifiedHaveInlineBody reports whether we have the function body for 3412 // fn, so we can inline it. 3413 func unifiedHaveInlineBody(fn *ir.Func) bool { 3414 if fn.Inl == nil { 3415 return false 3416 } 3417 3418 _, ok := bodyReaderFor(fn) 3419 return ok 3420 } 3421 3422 var inlgen = 0 3423 3424 // unifiedInlineCall implements inline.NewInline by re-reading the function 3425 // body from its Unified IR export data. 3426 func unifiedInlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { 3427 // TODO(mdempsky): Turn callerfn into an explicit parameter. 3428 callerfn := ir.CurFunc 3429 3430 pri, ok := bodyReaderFor(fn) 3431 if !ok { 3432 base.FatalfAt(call.Pos(), "cannot inline call to %v: missing inline body", fn) 3433 } 3434 3435 if fn.Inl.Body == nil { 3436 expandInline(fn, pri) 3437 } 3438 3439 r := pri.asReader(pkgbits.RelocBody, pkgbits.SyncFuncBody) 3440 3441 // TODO(mdempsky): This still feels clumsy. Can we do better? 3442 tmpfn := ir.NewFunc(fn.Pos()) 3443 tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), callerfn.Sym()) 3444 tmpfn.Closgen = callerfn.Closgen 3445 defer func() { callerfn.Closgen = tmpfn.Closgen }() 3446 3447 setType(tmpfn.Nname, fn.Type()) 3448 r.curfn = tmpfn 3449 3450 r.inlCaller = callerfn 3451 r.inlCall = call 3452 r.inlFunc = fn 3453 r.inlTreeIndex = inlIndex 3454 r.inlPosBases = make(map[*src.PosBase]*src.PosBase) 3455 3456 r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars)) 3457 for i, cv := range r.inlFunc.ClosureVars { 3458 r.closureVars[i] = cv.Outer 3459 } 3460 if len(r.closureVars) != 0 && r.hasTypeParams() { 3461 r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit 3462 } 3463 3464 r.funcargs(fn) 3465 3466 r.delayResults = fn.Inl.CanDelayResults 3467 3468 r.retlabel = typecheck.AutoLabel(".i") 3469 inlgen++ 3470 3471 init := ir.TakeInit(call) 3472 3473 // For normal function calls, the function callee expression 3474 // may contain side effects. Make sure to preserve these, 3475 // if necessary (#42703). 3476 if call.Op() == ir.OCALLFUNC { 3477 inline.CalleeEffects(&init, call.X) 3478 } 3479 3480 var args ir.Nodes 3481 if call.Op() == ir.OCALLMETH { 3482 base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck") 3483 } 3484 args.Append(call.Args...) 3485 3486 // Create assignment to declare and initialize inlvars. 3487 as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, r.inlvars, args) 3488 as2.Def = true 3489 var as2init ir.Nodes 3490 for _, name := range r.inlvars { 3491 if ir.IsBlank(name) { 3492 continue 3493 } 3494 // TODO(mdempsky): Use inlined position of name.Pos() instead? 3495 name := name.(*ir.Name) 3496 as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) 3497 name.Defn = as2 3498 } 3499 as2.SetInit(as2init) 3500 init.Append(typecheck.Stmt(as2)) 3501 3502 if !r.delayResults { 3503 // If not delaying retvars, declare and zero initialize the 3504 // result variables now. 3505 for _, name := range r.retvars { 3506 // TODO(mdempsky): Use inlined position of name.Pos() instead? 3507 name := name.(*ir.Name) 3508 init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) 3509 ras := ir.NewAssignStmt(call.Pos(), name, nil) 3510 init.Append(typecheck.Stmt(ras)) 3511 } 3512 } 3513 3514 // Add an inline mark just before the inlined body. 3515 // This mark is inline in the code so that it's a reasonable spot 3516 // to put a breakpoint. Not sure if that's really necessary or not 3517 // (in which case it could go at the end of the function instead). 3518 // Note issue 28603. 3519 init.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(r.inlTreeIndex))) 3520 3521 nparams := len(r.curfn.Dcl) 3522 3523 ir.WithFunc(r.curfn, func() { 3524 if !r.syntheticBody(call.Pos()) { 3525 assert(r.Bool()) // have body 3526 3527 r.curfn.Body = r.stmts() 3528 r.curfn.Endlineno = r.pos() 3529 } 3530 3531 // TODO(mdempsky): This shouldn't be necessary. Inlining might 3532 // read in new function/method declarations, which could 3533 // potentially be recursively inlined themselves; but we shouldn't 3534 // need to read in the non-inlined bodies for the declarations 3535 // themselves. But currently it's an easy fix to #50552. 3536 readBodies(typecheck.Target, true) 3537 3538 deadcode.Func(r.curfn) 3539 3540 // Replace any "return" statements within the function body. 3541 var edit func(ir.Node) ir.Node 3542 edit = func(n ir.Node) ir.Node { 3543 if ret, ok := n.(*ir.ReturnStmt); ok { 3544 n = typecheck.Stmt(r.inlReturn(ret)) 3545 } 3546 ir.EditChildren(n, edit) 3547 return n 3548 } 3549 edit(r.curfn) 3550 }) 3551 3552 body := ir.Nodes(r.curfn.Body) 3553 3554 // Quirkish: We need to eagerly prune variables added during 3555 // inlining, but removed by deadcode.FuncBody above. Unused 3556 // variables will get removed during stack frame layout anyway, but 3557 // len(fn.Dcl) ends up influencing things like autotmp naming. 3558 3559 used := usedLocals(body) 3560 3561 for i, name := range r.curfn.Dcl { 3562 if i < nparams || used.Has(name) { 3563 name.Curfn = callerfn 3564 callerfn.Dcl = append(callerfn.Dcl, name) 3565 3566 // Quirkish. TODO(mdempsky): Document why. 3567 if name.AutoTemp() { 3568 name.SetEsc(ir.EscUnknown) 3569 3570 if base.Flag.GenDwarfInl != 0 { 3571 name.SetInlLocal(true) 3572 } else { 3573 name.SetPos(r.inlCall.Pos()) 3574 } 3575 } 3576 } 3577 } 3578 3579 body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel)) 3580 3581 res := ir.NewInlinedCallExpr(call.Pos(), body, append([]ir.Node(nil), r.retvars...)) 3582 res.SetInit(init) 3583 res.SetType(call.Type()) 3584 res.SetTypecheck(1) 3585 3586 // Inlining shouldn't add any functions to todoBodies. 3587 assert(len(todoBodies) == 0) 3588 3589 return res 3590 } 3591 3592 // inlReturn returns a statement that can substitute for the given 3593 // return statement when inlining. 3594 func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt { 3595 pos := r.inlCall.Pos() 3596 3597 block := ir.TakeInit(ret) 3598 3599 if results := ret.Results; len(results) != 0 { 3600 assert(len(r.retvars) == len(results)) 3601 3602 as2 := ir.NewAssignListStmt(pos, ir.OAS2, append([]ir.Node(nil), r.retvars...), ret.Results) 3603 3604 if r.delayResults { 3605 for _, name := range r.retvars { 3606 // TODO(mdempsky): Use inlined position of name.Pos() instead? 3607 name := name.(*ir.Name) 3608 block.Append(ir.NewDecl(pos, ir.ODCL, name)) 3609 name.Defn = as2 3610 } 3611 } 3612 3613 block.Append(as2) 3614 } 3615 3616 block.Append(ir.NewBranchStmt(pos, ir.OGOTO, r.retlabel)) 3617 return ir.NewBlockStmt(pos, block) 3618 } 3619 3620 // expandInline reads in an extra copy of IR to populate 3621 // fn.Inl.{Dcl,Body}. 3622 func expandInline(fn *ir.Func, pri pkgReaderIndex) { 3623 // TODO(mdempsky): Remove this function. It's currently needed by 3624 // dwarfgen/dwarf.go:preInliningDcls, which requires fn.Inl.Dcl to 3625 // create abstract function DIEs. But we should be able to provide it 3626 // with the same information some other way. 3627 3628 fndcls := len(fn.Dcl) 3629 topdcls := len(typecheck.Target.Decls) 3630 3631 tmpfn := ir.NewFunc(fn.Pos()) 3632 tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), fn.Sym()) 3633 tmpfn.ClosureVars = fn.ClosureVars 3634 3635 { 3636 r := pri.asReader(pkgbits.RelocBody, pkgbits.SyncFuncBody) 3637 setType(tmpfn.Nname, fn.Type()) 3638 3639 // Don't change parameter's Sym/Nname fields. 3640 r.funarghack = true 3641 3642 r.funcBody(tmpfn) 3643 3644 ir.WithFunc(tmpfn, func() { 3645 deadcode.Func(tmpfn) 3646 }) 3647 } 3648 3649 used := usedLocals(tmpfn.Body) 3650 3651 for _, name := range tmpfn.Dcl { 3652 if name.Class != ir.PAUTO || used.Has(name) { 3653 name.Curfn = fn 3654 fn.Inl.Dcl = append(fn.Inl.Dcl, name) 3655 } 3656 } 3657 fn.Inl.Body = tmpfn.Body 3658 3659 // Double check that we didn't change fn.Dcl by accident. 3660 assert(fndcls == len(fn.Dcl)) 3661 3662 // typecheck.Stmts may have added function literals to 3663 // typecheck.Target.Decls. Remove them again so we don't risk trying 3664 // to compile them multiple times. 3665 typecheck.Target.Decls = typecheck.Target.Decls[:topdcls] 3666 } 3667 3668 // usedLocals returns a set of local variables that are used within body. 3669 func usedLocals(body []ir.Node) ir.NameSet { 3670 var used ir.NameSet 3671 ir.VisitList(body, func(n ir.Node) { 3672 if n, ok := n.(*ir.Name); ok && n.Op() == ir.ONAME && n.Class == ir.PAUTO { 3673 used.Add(n) 3674 } 3675 }) 3676 return used 3677 } 3678 3679 // @@@ Method wrappers 3680 3681 // needWrapperTypes lists types for which we may need to generate 3682 // method wrappers. 3683 var needWrapperTypes []*types.Type 3684 3685 // haveWrapperTypes lists types for which we know we already have 3686 // method wrappers, because we found the type in an imported package. 3687 var haveWrapperTypes []*types.Type 3688 3689 // needMethodValueWrappers lists methods for which we may need to 3690 // generate method value wrappers. 3691 var needMethodValueWrappers []methodValueWrapper 3692 3693 // haveMethodValueWrappers lists methods for which we know we already 3694 // have method value wrappers, because we found it in an imported 3695 // package. 3696 var haveMethodValueWrappers []methodValueWrapper 3697 3698 type methodValueWrapper struct { 3699 rcvr *types.Type 3700 method *types.Field 3701 } 3702 3703 func (r *reader) needWrapper(typ *types.Type) { 3704 if typ.IsPtr() { 3705 return 3706 } 3707 3708 // If a type was found in an imported package, then we can assume 3709 // that package (or one of its transitive dependencies) already 3710 // generated method wrappers for it. 3711 if r.importedDef() { 3712 haveWrapperTypes = append(haveWrapperTypes, typ) 3713 } else { 3714 needWrapperTypes = append(needWrapperTypes, typ) 3715 } 3716 } 3717 3718 // importedDef reports whether r is reading from an imported and 3719 // non-generic element. 3720 // 3721 // If a type was found in an imported package, then we can assume that 3722 // package (or one of its transitive dependencies) already generated 3723 // method wrappers for it. 3724 // 3725 // Exception: If we're instantiating an imported generic type or 3726 // function, we might be instantiating it with type arguments not 3727 // previously seen before. 3728 // 3729 // TODO(mdempsky): Distinguish when a generic function or type was 3730 // instantiated in an imported package so that we can add types to 3731 // haveWrapperTypes instead. 3732 func (r *reader) importedDef() bool { 3733 return r.p != localPkgReader && !r.hasTypeParams() 3734 } 3735 3736 func MakeWrappers(target *ir.Package) { 3737 // Only unified IR emits its own wrappers. 3738 if base.Debug.Unified == 0 { 3739 return 3740 } 3741 3742 // always generate a wrapper for error.Error (#29304) 3743 needWrapperTypes = append(needWrapperTypes, types.ErrorType) 3744 3745 seen := make(map[string]*types.Type) 3746 3747 for _, typ := range haveWrapperTypes { 3748 wrapType(typ, target, seen, false) 3749 } 3750 haveWrapperTypes = nil 3751 3752 for _, typ := range needWrapperTypes { 3753 wrapType(typ, target, seen, true) 3754 } 3755 needWrapperTypes = nil 3756 3757 for _, wrapper := range haveMethodValueWrappers { 3758 wrapMethodValue(wrapper.rcvr, wrapper.method, target, false) 3759 } 3760 haveMethodValueWrappers = nil 3761 3762 for _, wrapper := range needMethodValueWrappers { 3763 wrapMethodValue(wrapper.rcvr, wrapper.method, target, true) 3764 } 3765 needMethodValueWrappers = nil 3766 } 3767 3768 func wrapType(typ *types.Type, target *ir.Package, seen map[string]*types.Type, needed bool) { 3769 key := typ.LinkString() 3770 if prev := seen[key]; prev != nil { 3771 if !types.Identical(typ, prev) { 3772 base.Fatalf("collision: types %v and %v have link string %q", typ, prev, key) 3773 } 3774 return 3775 } 3776 seen[key] = typ 3777 3778 if !needed { 3779 // Only called to add to 'seen'. 3780 return 3781 } 3782 3783 if !typ.IsInterface() { 3784 typecheck.CalcMethods(typ) 3785 } 3786 for _, meth := range typ.AllMethods().Slice() { 3787 if meth.Sym.IsBlank() || !meth.IsMethod() { 3788 base.FatalfAt(meth.Pos, "invalid method: %v", meth) 3789 } 3790 3791 methodWrapper(0, typ, meth, target) 3792 3793 // For non-interface types, we also want *T wrappers. 3794 if !typ.IsInterface() { 3795 methodWrapper(1, typ, meth, target) 3796 3797 // For not-in-heap types, *T is a scalar, not pointer shaped, 3798 // so the interface wrappers use **T. 3799 if typ.NotInHeap() { 3800 methodWrapper(2, typ, meth, target) 3801 } 3802 } 3803 } 3804 } 3805 3806 func methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) { 3807 wrapper := tbase 3808 for i := 0; i < derefs; i++ { 3809 wrapper = types.NewPtr(wrapper) 3810 } 3811 3812 sym := ir.MethodSym(wrapper, method.Sym) 3813 base.Assertf(!sym.Siggen(), "already generated wrapper %v", sym) 3814 sym.SetSiggen(true) 3815 3816 wrappee := method.Type.Recv().Type 3817 if types.Identical(wrapper, wrappee) || 3818 !types.IsMethodApplicable(wrapper, method) || 3819 !reflectdata.NeedEmit(tbase) { 3820 return 3821 } 3822 3823 // TODO(mdempsky): Use method.Pos instead? 3824 pos := base.AutogeneratedPos 3825 3826 fn := newWrapperFunc(pos, sym, wrapper, method) 3827 3828 var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name) 3829 3830 // For simple *T wrappers around T methods, panicwrap produces a 3831 // nicer panic message. 3832 if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) { 3833 cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node)) 3834 then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)} 3835 fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil)) 3836 } 3837 3838 // typecheck will add one implicit deref, if necessary, 3839 // but not-in-heap types require more for their **T wrappers. 3840 for i := 1; i < derefs; i++ { 3841 recv = Implicit(ir.NewStarExpr(pos, recv)) 3842 } 3843 3844 addTailCall(pos, fn, recv, method) 3845 3846 finishWrapperFunc(fn, target) 3847 } 3848 3849 func wrapMethodValue(recvType *types.Type, method *types.Field, target *ir.Package, needed bool) { 3850 sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm") 3851 if sym.Uniq() { 3852 return 3853 } 3854 sym.SetUniq(true) 3855 3856 // TODO(mdempsky): Use method.Pos instead? 3857 pos := base.AutogeneratedPos 3858 3859 fn := newWrapperFunc(pos, sym, nil, method) 3860 sym.Def = fn.Nname 3861 3862 // Declare and initialize variable holding receiver. 3863 recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType) 3864 3865 if !needed { 3866 typecheck.Func(fn) 3867 return 3868 } 3869 3870 addTailCall(pos, fn, recv, method) 3871 3872 finishWrapperFunc(fn, target) 3873 } 3874 3875 func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func { 3876 fn := ir.NewFunc(pos) 3877 fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers? 3878 3879 name := ir.NewNameAt(pos, sym) 3880 ir.MarkFunc(name) 3881 name.Func = fn 3882 name.Defn = fn 3883 fn.Nname = name 3884 3885 sig := newWrapperType(wrapper, method) 3886 setType(name, sig) 3887 3888 // TODO(mdempsky): De-duplicate with similar logic in funcargs. 3889 defParams := func(class ir.Class, params *types.Type) { 3890 for _, param := range params.FieldSlice() { 3891 name := ir.NewNameAt(param.Pos, param.Sym) 3892 name.Class = class 3893 setType(name, param.Type) 3894 3895 name.Curfn = fn 3896 fn.Dcl = append(fn.Dcl, name) 3897 3898 param.Nname = name 3899 } 3900 } 3901 3902 defParams(ir.PPARAM, sig.Recvs()) 3903 defParams(ir.PPARAM, sig.Params()) 3904 defParams(ir.PPARAMOUT, sig.Results()) 3905 3906 return fn 3907 } 3908 3909 func finishWrapperFunc(fn *ir.Func, target *ir.Package) { 3910 typecheck.Func(fn) 3911 3912 ir.WithFunc(fn, func() { 3913 typecheck.Stmts(fn.Body) 3914 }) 3915 3916 // We generate wrappers after the global inlining pass, 3917 // so we're responsible for applying inlining ourselves here. 3918 // TODO(prattmic): plumb PGO. 3919 inline.InlineCalls(fn, nil) 3920 3921 // The body of wrapper function after inlining may reveal new ir.OMETHVALUE node, 3922 // we don't know whether wrapper function has been generated for it or not, so 3923 // generate one immediately here. 3924 ir.VisitList(fn.Body, func(n ir.Node) { 3925 if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE { 3926 wrapMethodValue(n.X.Type(), n.Selection, target, true) 3927 } 3928 }) 3929 3930 target.Decls = append(target.Decls, fn) 3931 } 3932 3933 // newWrapperType returns a copy of the given signature type, but with 3934 // the receiver parameter type substituted with recvType. 3935 // If recvType is nil, newWrapperType returns a signature 3936 // without a receiver parameter. 3937 func newWrapperType(recvType *types.Type, method *types.Field) *types.Type { 3938 clone := func(params []*types.Field) []*types.Field { 3939 res := make([]*types.Field, len(params)) 3940 for i, param := range params { 3941 sym := param.Sym 3942 if sym == nil || sym.Name == "_" { 3943 sym = typecheck.LookupNum(".anon", i) 3944 } 3945 res[i] = types.NewField(param.Pos, sym, param.Type) 3946 res[i].SetIsDDD(param.IsDDD()) 3947 } 3948 return res 3949 } 3950 3951 sig := method.Type 3952 3953 var recv *types.Field 3954 if recvType != nil { 3955 recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType) 3956 } 3957 params := clone(sig.Params().FieldSlice()) 3958 results := clone(sig.Results().FieldSlice()) 3959 3960 return types.NewSignature(types.NoPkg, recv, nil, params, results) 3961 } 3962 3963 func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) { 3964 sig := fn.Nname.Type() 3965 args := make([]ir.Node, sig.NumParams()) 3966 for i, param := range sig.Params().FieldSlice() { 3967 args[i] = param.Nname.(*ir.Name) 3968 } 3969 3970 // TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper. 3971 // Not urgent though, because tail calls are currently incompatible with regabi anyway. 3972 3973 fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls? 3974 3975 dot := ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym) 3976 call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr) 3977 3978 if method.Type.NumResults() == 0 { 3979 fn.Body.Append(call) 3980 return 3981 } 3982 3983 ret := ir.NewReturnStmt(pos, nil) 3984 ret.Results = []ir.Node{call} 3985 fn.Body.Append(ret) 3986 } 3987 3988 func setBasePos(pos src.XPos) { 3989 // Set the position for any error messages we might print (e.g. too large types). 3990 base.Pos = pos 3991 } 3992 3993 // dictParamName is the name of the synthetic dictionary parameter 3994 // added to shaped functions. 3995 // 3996 // N.B., this variable name is known to Delve: 3997 // https://github.com/go-delve/delve/blob/cb91509630529e6055be845688fd21eb89ae8714/pkg/proc/eval.go#L28 3998 const dictParamName = ".dict" 3999 4000 // shapeSig returns a copy of fn's signature, except adding a 4001 // dictionary parameter and promoting the receiver parameter (if any) 4002 // to a normal parameter. 4003 // 4004 // The parameter types.Fields are all copied too, so their Nname 4005 // fields can be initialized for use by the shape function. 4006 func shapeSig(fn *ir.Func, dict *readerDict) *types.Type { 4007 sig := fn.Nname.Type() 4008 oldRecv := sig.Recv() 4009 4010 var recv *types.Field 4011 if oldRecv != nil { 4012 recv = types.NewField(oldRecv.Pos, oldRecv.Sym, oldRecv.Type) 4013 } 4014 4015 params := make([]*types.Field, 1+sig.Params().Fields().Len()) 4016 params[0] = types.NewField(fn.Pos(), fn.Sym().Pkg.Lookup(dictParamName), types.NewPtr(dict.varType())) 4017 for i, param := range sig.Params().Fields().Slice() { 4018 d := types.NewField(param.Pos, param.Sym, param.Type) 4019 d.SetIsDDD(param.IsDDD()) 4020 params[1+i] = d 4021 } 4022 4023 results := make([]*types.Field, sig.Results().Fields().Len()) 4024 for i, result := range sig.Results().Fields().Slice() { 4025 results[i] = types.NewField(result.Pos, result.Sym, result.Type) 4026 } 4027 4028 return types.NewSignature(types.LocalPkg, recv, nil, params, results) 4029 }