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 5package noder 6 7import ( 8 "fmt" 9 "go/constant" 10 "go/token" 11 "go/version" 12 "internal/buildcfg" 13 "internal/pkgbits" 14 "os" 15 "strings" 16 17 "cmd/compile/internal/base" 18 "cmd/compile/internal/ir" 19 "cmd/compile/internal/syntax" 20 "cmd/compile/internal/types" 21 "cmd/compile/internal/types2" 22) 23 24// This file implements the Unified IR package writer and defines the 25// Unified IR export data format. 26// 27// Low-level coding details (e.g., byte-encoding of individual 28// primitive values, or handling element bitstreams and 29// cross-references) are handled by internal/pkgbits, so here we only 30// concern ourselves with higher-level worries like mapping Go 31// language constructs into elements. 32 33// There are two central types in the writing process: the "writer" 34// type handles writing out individual elements, while the "pkgWriter" 35// type keeps track of which elements have already been created. 36// 37// For each sort of "thing" (e.g., position, package, object, type) 38// that can be written into the export data, there are generally 39// several methods that work together: 40// 41// - writer.thing handles writing out a *use* of a thing, which often 42// means writing a relocation to that thing's encoded index. 43// 44// - pkgWriter.thingIdx handles reserving an index for a thing, and 45// writing out any elements needed for the thing. 46// 47// - writer.doThing handles writing out the *definition* of a thing, 48// which in general is a mix of low-level coding primitives (e.g., 49// ints and strings) or uses of other things. 50// 51// A design goal of Unified IR is to have a single, canonical writer 52// implementation, but multiple reader implementations each tailored 53// to their respective needs. For example, within cmd/compile's own 54// backend, inlining is implemented largely by just re-running the 55// function body reading code. 56 57// TODO(mdempsky): Add an importer for Unified IR to the x/tools repo, 58// and better document the file format boundary between public and 59// private data. 60 61// A pkgWriter constructs Unified IR export data from the results of 62// running the types2 type checker on a Go compilation unit. 63type pkgWriter struct { 64 pkgbits.PkgEncoder 65 66 m posMap 67 curpkg *types2.Package 68 info *types2.Info 69 rangeFuncBodyClosures map[*syntax.FuncLit]bool // non-public information, e.g., which functions are closures range function bodies? 70 71 // Indices for previously written syntax and types2 things. 72 73 posBasesIdx map[*syntax.PosBase]pkgbits.Index 74 pkgsIdx map[*types2.Package]pkgbits.Index 75 typsIdx map[types2.Type]pkgbits.Index 76 objsIdx map[types2.Object]pkgbits.Index 77 78 // Maps from types2.Objects back to their syntax.Decl. 79 80 funDecls map[*types2.Func]*syntax.FuncDecl 81 typDecls map[*types2.TypeName]typeDeclGen 82 83 // linknames maps package-scope objects to their linker symbol name, 84 // if specified by a //go:linkname directive. 85 linknames map[types2.Object]string 86 87 // cgoPragmas accumulates any //go:cgo_* pragmas that need to be 88 // passed through to cmd/link. 89 cgoPragmas [][]string 90} 91 92// newPkgWriter returns an initialized pkgWriter for the specified 93// package. 94func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo map[*syntax.FuncLit]bool) *pkgWriter { 95 return &pkgWriter{ 96 PkgEncoder: pkgbits.NewPkgEncoder(base.Debug.SyncFrames), 97 98 m: m, 99 curpkg: pkg, 100 info: info, 101 rangeFuncBodyClosures: otherInfo, 102 103 pkgsIdx: make(map[*types2.Package]pkgbits.Index), 104 objsIdx: make(map[types2.Object]pkgbits.Index), 105 typsIdx: make(map[types2.Type]pkgbits.Index), 106 107 posBasesIdx: make(map[*syntax.PosBase]pkgbits.Index), 108 109 funDecls: make(map[*types2.Func]*syntax.FuncDecl), 110 typDecls: make(map[*types2.TypeName]typeDeclGen), 111 112 linknames: make(map[types2.Object]string), 113 } 114} 115 116// errorf reports a user error about thing p. 117func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) { 118 base.ErrorfAt(pw.m.pos(p), 0, msg, args...) 119} 120 121// fatalf reports an internal compiler error about thing p. 122func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) { 123 base.FatalfAt(pw.m.pos(p), msg, args...) 124} 125 126// unexpected reports a fatal error about a thing of unexpected 127// dynamic type. 128func (pw *pkgWriter) unexpected(what string, p poser) { 129 pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p) 130} 131 132func (pw *pkgWriter) typeAndValue(x syntax.Expr) syntax.TypeAndValue { 133 tv, ok := pw.maybeTypeAndValue(x) 134 if !ok { 135 pw.fatalf(x, "missing Types entry: %v", syntax.String(x)) 136 } 137 return tv 138} 139 140func (pw *pkgWriter) maybeTypeAndValue(x syntax.Expr) (syntax.TypeAndValue, bool) { 141 tv := x.GetTypeInfo() 142 143 // If x is a generic function whose type arguments are inferred 144 // from assignment context, then we need to find its inferred type 145 // in Info.Instances instead. 146 if name, ok := x.(*syntax.Name); ok { 147 if inst, ok := pw.info.Instances[name]; ok { 148 tv.Type = inst.Type 149 } 150 } 151 152 return tv, tv.Type != nil 153} 154 155// typeOf returns the Type of the given value expression. 156func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type { 157 tv := pw.typeAndValue(expr) 158 if !tv.IsValue() { 159 pw.fatalf(expr, "expected value: %v", syntax.String(expr)) 160 } 161 return tv.Type 162} 163 164// A writer provides APIs for writing out an individual element. 165type writer struct { 166 p *pkgWriter 167 168 pkgbits.Encoder 169 170 // sig holds the signature for the current function body, if any. 171 sig *types2.Signature 172 173 // TODO(mdempsky): We should be able to prune localsIdx whenever a 174 // scope closes, and then maybe we can just use the same map for 175 // storing the TypeParams too (as their TypeName instead). 176 177 // localsIdx tracks any local variables declared within this 178 // function body. It's unused for writing out non-body things. 179 localsIdx map[*types2.Var]int 180 181 // closureVars tracks any free variables that are referenced by this 182 // function body. It's unused for writing out non-body things. 183 closureVars []posVar 184 closureVarsIdx map[*types2.Var]int // index of previously seen free variables 185 186 dict *writerDict 187 188 // derived tracks whether the type being written out references any 189 // type parameters. It's unused for writing non-type things. 190 derived bool 191} 192 193// A writerDict tracks types and objects that are used by a declaration. 194type writerDict struct { 195 // implicits is a slice of type parameters from the enclosing 196 // declarations. 197 implicits []*types2.TypeParam 198 199 // derived is a slice of type indices for computing derived types 200 // (i.e., types that depend on the declaration's type parameters). 201 derived []derivedInfo 202 203 // derivedIdx maps a Type to its corresponding index within the 204 // derived slice, if present. 205 derivedIdx map[types2.Type]pkgbits.Index 206 207 // These slices correspond to entries in the runtime dictionary. 208 typeParamMethodExprs []writerMethodExprInfo 209 subdicts []objInfo 210 rtypes []typeInfo 211 itabs []itabInfo 212} 213 214type itabInfo struct { 215 typ typeInfo 216 iface typeInfo 217} 218 219// typeParamIndex returns the index of the given type parameter within 220// the dictionary. This may differ from typ.Index() when there are 221// implicit type parameters due to defined types declared within a 222// generic function or method. 223func (dict *writerDict) typeParamIndex(typ *types2.TypeParam) int { 224 for idx, implicit := range dict.implicits { 225 if implicit == typ { 226 return idx 227 } 228 } 229 230 return len(dict.implicits) + typ.Index() 231} 232 233// A derivedInfo represents a reference to an encoded generic Go type. 234type derivedInfo struct { 235 idx pkgbits.Index 236 needed bool // TODO(mdempsky): Remove. 237} 238 239// A typeInfo represents a reference to an encoded Go type. 240// 241// If derived is true, then the typeInfo represents a generic Go type 242// that contains type parameters. In this case, idx is an index into 243// the readerDict.derived{,Types} arrays. 244// 245// Otherwise, the typeInfo represents a non-generic Go type, and idx 246// is an index into the reader.typs array instead. 247type typeInfo struct { 248 idx pkgbits.Index 249 derived bool 250} 251 252// An objInfo represents a reference to an encoded, instantiated (if 253// applicable) Go object. 254type objInfo struct { 255 idx pkgbits.Index // index for the generic function declaration 256 explicits []typeInfo // info for the type arguments 257} 258 259// A selectorInfo represents a reference to an encoded field or method 260// name (i.e., objects that can only be accessed using selector 261// expressions). 262type selectorInfo struct { 263 pkgIdx pkgbits.Index 264 nameIdx pkgbits.Index 265} 266 267// anyDerived reports whether any of info's explicit type arguments 268// are derived types. 269func (info objInfo) anyDerived() bool { 270 for _, explicit := range info.explicits { 271 if explicit.derived { 272 return true 273 } 274 } 275 return false 276} 277 278// equals reports whether info and other represent the same Go object 279// (i.e., same base object and identical type arguments, if any). 280func (info objInfo) equals(other objInfo) bool { 281 if info.idx != other.idx { 282 return false 283 } 284 assert(len(info.explicits) == len(other.explicits)) 285 for i, targ := range info.explicits { 286 if targ != other.explicits[i] { 287 return false 288 } 289 } 290 return true 291} 292 293type writerMethodExprInfo struct { 294 typeParamIdx int 295 methodInfo selectorInfo 296} 297 298// typeParamMethodExprIdx returns the index where the given encoded 299// method expression function pointer appears within this dictionary's 300// type parameters method expressions section, adding it if necessary. 301func (dict *writerDict) typeParamMethodExprIdx(typeParamIdx int, methodInfo selectorInfo) int { 302 newInfo := writerMethodExprInfo{typeParamIdx, methodInfo} 303 304 for idx, oldInfo := range dict.typeParamMethodExprs { 305 if oldInfo == newInfo { 306 return idx 307 } 308 } 309 310 idx := len(dict.typeParamMethodExprs) 311 dict.typeParamMethodExprs = append(dict.typeParamMethodExprs, newInfo) 312 return idx 313} 314 315// subdictIdx returns the index where the given encoded object's 316// runtime dictionary appears within this dictionary's subdictionary 317// section, adding it if necessary. 318func (dict *writerDict) subdictIdx(newInfo objInfo) int { 319 for idx, oldInfo := range dict.subdicts { 320 if oldInfo.equals(newInfo) { 321 return idx 322 } 323 } 324 325 idx := len(dict.subdicts) 326 dict.subdicts = append(dict.subdicts, newInfo) 327 return idx 328} 329 330// rtypeIdx returns the index where the given encoded type's 331// *runtime._type value appears within this dictionary's rtypes 332// section, adding it if necessary. 333func (dict *writerDict) rtypeIdx(newInfo typeInfo) int { 334 for idx, oldInfo := range dict.rtypes { 335 if oldInfo == newInfo { 336 return idx 337 } 338 } 339 340 idx := len(dict.rtypes) 341 dict.rtypes = append(dict.rtypes, newInfo) 342 return idx 343} 344 345// itabIdx returns the index where the given encoded type pair's 346// *runtime.itab value appears within this dictionary's itabs section, 347// adding it if necessary. 348func (dict *writerDict) itabIdx(typInfo, ifaceInfo typeInfo) int { 349 newInfo := itabInfo{typInfo, ifaceInfo} 350 351 for idx, oldInfo := range dict.itabs { 352 if oldInfo == newInfo { 353 return idx 354 } 355 } 356 357 idx := len(dict.itabs) 358 dict.itabs = append(dict.itabs, newInfo) 359 return idx 360} 361 362func (pw *pkgWriter) newWriter(k pkgbits.RelocKind, marker pkgbits.SyncMarker) *writer { 363 return &writer{ 364 Encoder: pw.NewEncoder(k, marker), 365 p: pw, 366 } 367} 368 369// @@@ Positions 370 371// pos writes the position of p into the element bitstream. 372func (w *writer) pos(p poser) { 373 w.Sync(pkgbits.SyncPos) 374 pos := p.Pos() 375 376 // TODO(mdempsky): Track down the remaining cases here and fix them. 377 if !w.Bool(pos.IsKnown()) { 378 return 379 } 380 381 // TODO(mdempsky): Delta encoding. 382 w.posBase(pos.Base()) 383 w.Uint(pos.Line()) 384 w.Uint(pos.Col()) 385} 386 387// posBase writes a reference to the given PosBase into the element 388// bitstream. 389func (w *writer) posBase(b *syntax.PosBase) { 390 w.Reloc(pkgbits.RelocPosBase, w.p.posBaseIdx(b)) 391} 392 393// posBaseIdx returns the index for the given PosBase. 394func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) pkgbits.Index { 395 if idx, ok := pw.posBasesIdx[b]; ok { 396 return idx 397 } 398 399 w := pw.newWriter(pkgbits.RelocPosBase, pkgbits.SyncPosBase) 400 w.p.posBasesIdx[b] = w.Idx 401 402 w.String(trimFilename(b)) 403 404 if !w.Bool(b.IsFileBase()) { 405 w.pos(b) 406 w.Uint(b.Line()) 407 w.Uint(b.Col()) 408 } 409 410 return w.Flush() 411} 412 413// @@@ Packages 414 415// pkg writes a use of the given Package into the element bitstream. 416func (w *writer) pkg(pkg *types2.Package) { 417 w.pkgRef(w.p.pkgIdx(pkg)) 418} 419 420func (w *writer) pkgRef(idx pkgbits.Index) { 421 w.Sync(pkgbits.SyncPkg) 422 w.Reloc(pkgbits.RelocPkg, idx) 423} 424 425// pkgIdx returns the index for the given package, adding it to the 426// package export data if needed. 427func (pw *pkgWriter) pkgIdx(pkg *types2.Package) pkgbits.Index { 428 if idx, ok := pw.pkgsIdx[pkg]; ok { 429 return idx 430 } 431 432 w := pw.newWriter(pkgbits.RelocPkg, pkgbits.SyncPkgDef) 433 pw.pkgsIdx[pkg] = w.Idx 434 435 // The universe and package unsafe need to be handled specially by 436 // importers anyway, so we serialize them using just their package 437 // path. This ensures that readers don't confuse them for 438 // user-defined packages. 439 switch pkg { 440 case nil: // universe 441 w.String("builtin") // same package path used by godoc 442 case types2.Unsafe: 443 w.String("unsafe") 444 default: 445 // TODO(mdempsky): Write out pkg.Path() for curpkg too. 446 var path string 447 if pkg != w.p.curpkg { 448 path = pkg.Path() 449 } 450 base.Assertf(path != "builtin" && path != "unsafe", "unexpected path for user-defined package: %q", path) 451 w.String(path) 452 w.String(pkg.Name()) 453 454 w.Len(len(pkg.Imports())) 455 for _, imp := range pkg.Imports() { 456 w.pkg(imp) 457 } 458 } 459 460 return w.Flush() 461} 462 463// @@@ Types 464 465var ( 466 anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName) 467 comparableTypeName = types2.Universe.Lookup("comparable").(*types2.TypeName) 468 runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName) 469) 470 471// typ writes a use of the given type into the bitstream. 472func (w *writer) typ(typ types2.Type) { 473 w.typInfo(w.p.typIdx(typ, w.dict)) 474} 475 476// typInfo writes a use of the given type (specified as a typeInfo 477// instead) into the bitstream. 478func (w *writer) typInfo(info typeInfo) { 479 w.Sync(pkgbits.SyncType) 480 if w.Bool(info.derived) { 481 w.Len(int(info.idx)) 482 w.derived = true 483 } else { 484 w.Reloc(pkgbits.RelocType, info.idx) 485 } 486} 487 488// typIdx returns the index where the export data description of type 489// can be read back in. If no such index exists yet, it's created. 490// 491// typIdx also reports whether typ is a derived type; that is, whether 492// its identity depends on type parameters. 493func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { 494 // Strip non-global aliases, because they only appear in inline 495 // bodies anyway. Otherwise, they can cause types.Sym collisions 496 // (e.g., "main.C" for both of the local type aliases in 497 // test/fixedbugs/issue50190.go). 498 for { 499 if alias, ok := typ.(*types2.Alias); ok && !isGlobal(alias.Obj()) { 500 typ = alias.Rhs() 501 } else { 502 break 503 } 504 } 505 506 if idx, ok := pw.typsIdx[typ]; ok { 507 return typeInfo{idx: idx, derived: false} 508 } 509 if dict != nil { 510 if idx, ok := dict.derivedIdx[typ]; ok { 511 return typeInfo{idx: idx, derived: true} 512 } 513 } 514 515 w := pw.newWriter(pkgbits.RelocType, pkgbits.SyncTypeIdx) 516 w.dict = dict 517 518 switch typ := typ.(type) { 519 default: 520 base.Fatalf("unexpected type: %v (%T)", typ, typ) 521 522 case *types2.Basic: 523 switch kind := typ.Kind(); { 524 case kind == types2.Invalid: 525 base.Fatalf("unexpected types2.Invalid") 526 527 case types2.Typ[kind] == typ: 528 w.Code(pkgbits.TypeBasic) 529 w.Len(int(kind)) 530 531 default: 532 // Handle "byte" and "rune" as references to their TypeNames. 533 obj := types2.Universe.Lookup(typ.Name()).(*types2.TypeName) 534 assert(obj.Type() == typ) 535 536 w.Code(pkgbits.TypeNamed) 537 w.namedType(obj, nil) 538 } 539 540 case *types2.Named: 541 w.Code(pkgbits.TypeNamed) 542 w.namedType(splitNamed(typ)) 543 544 case *types2.Alias: 545 w.Code(pkgbits.TypeNamed) 546 w.namedType(splitAlias(typ)) 547 548 case *types2.TypeParam: 549 w.derived = true 550 w.Code(pkgbits.TypeTypeParam) 551 w.Len(w.dict.typeParamIndex(typ)) 552 553 case *types2.Array: 554 w.Code(pkgbits.TypeArray) 555 w.Uint64(uint64(typ.Len())) 556 w.typ(typ.Elem()) 557 558 case *types2.Chan: 559 w.Code(pkgbits.TypeChan) 560 w.Len(int(typ.Dir())) 561 w.typ(typ.Elem()) 562 563 case *types2.Map: 564 w.Code(pkgbits.TypeMap) 565 w.typ(typ.Key()) 566 w.typ(typ.Elem()) 567 568 case *types2.Pointer: 569 w.Code(pkgbits.TypePointer) 570 w.typ(typ.Elem()) 571 572 case *types2.Signature: 573 base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ) 574 w.Code(pkgbits.TypeSignature) 575 w.signature(typ) 576 577 case *types2.Slice: 578 w.Code(pkgbits.TypeSlice) 579 w.typ(typ.Elem()) 580 581 case *types2.Struct: 582 w.Code(pkgbits.TypeStruct) 583 w.structType(typ) 584 585 case *types2.Interface: 586 // Handle "any" as reference to its TypeName. 587 // The underlying "any" interface is canonical, so this logic handles both 588 // GODEBUG=gotypesalias=1 (when any is represented as a types2.Alias), and 589 // gotypesalias=0. 590 if types2.Unalias(typ) == types2.Unalias(anyTypeName.Type()) { 591 w.Code(pkgbits.TypeNamed) 592 w.obj(anyTypeName, nil) 593 break 594 } 595 596 w.Code(pkgbits.TypeInterface) 597 w.interfaceType(typ) 598 599 case *types2.Union: 600 w.Code(pkgbits.TypeUnion) 601 w.unionType(typ) 602 } 603 604 if w.derived { 605 idx := pkgbits.Index(len(dict.derived)) 606 dict.derived = append(dict.derived, derivedInfo{idx: w.Flush()}) 607 dict.derivedIdx[typ] = idx 608 return typeInfo{idx: idx, derived: true} 609 } 610 611 pw.typsIdx[typ] = w.Idx 612 return typeInfo{idx: w.Flush(), derived: false} 613} 614 615// namedType writes a use of the given named type into the bitstream. 616func (w *writer) namedType(obj *types2.TypeName, targs *types2.TypeList) { 617 // Named types that are declared within a generic function (and 618 // thus have implicit type parameters) are always derived types. 619 if w.p.hasImplicitTypeParams(obj) { 620 w.derived = true 621 } 622 623 w.obj(obj, targs) 624} 625 626func (w *writer) structType(typ *types2.Struct) { 627 w.Len(typ.NumFields()) 628 for i := 0; i < typ.NumFields(); i++ { 629 f := typ.Field(i) 630 w.pos(f) 631 w.selector(f) 632 w.typ(f.Type()) 633 w.String(typ.Tag(i)) 634 w.Bool(f.Embedded()) 635 } 636} 637 638func (w *writer) unionType(typ *types2.Union) { 639 w.Len(typ.Len()) 640 for i := 0; i < typ.Len(); i++ { 641 t := typ.Term(i) 642 w.Bool(t.Tilde()) 643 w.typ(t.Type()) 644 } 645} 646 647func (w *writer) interfaceType(typ *types2.Interface) { 648 // If typ has no embedded types but it's not a basic interface, then 649 // the natural description we write out below will fail to 650 // reconstruct it. 651 if typ.NumEmbeddeds() == 0 && !typ.IsMethodSet() { 652 // Currently, this can only happen for the underlying Interface of 653 // "comparable", which is needed to handle type declarations like 654 // "type C comparable". 655 assert(typ == comparableTypeName.Type().(*types2.Named).Underlying()) 656 657 // Export as "interface{ comparable }". 658 w.Len(0) // NumExplicitMethods 659 w.Len(1) // NumEmbeddeds 660 w.Bool(false) // IsImplicit 661 w.typ(comparableTypeName.Type()) // EmbeddedType(0) 662 return 663 } 664 665 w.Len(typ.NumExplicitMethods()) 666 w.Len(typ.NumEmbeddeds()) 667 668 if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 1 { 669 w.Bool(typ.IsImplicit()) 670 } else { 671 // Implicit interfaces always have 0 explicit methods and 1 672 // embedded type, so we skip writing out the implicit flag 673 // otherwise as a space optimization. 674 assert(!typ.IsImplicit()) 675 } 676 677 for i := 0; i < typ.NumExplicitMethods(); i++ { 678 m := typ.ExplicitMethod(i) 679 sig := m.Type().(*types2.Signature) 680 assert(sig.TypeParams() == nil) 681 682 w.pos(m) 683 w.selector(m) 684 w.signature(sig) 685 } 686 687 for i := 0; i < typ.NumEmbeddeds(); i++ { 688 w.typ(typ.EmbeddedType(i)) 689 } 690} 691 692func (w *writer) signature(sig *types2.Signature) { 693 w.Sync(pkgbits.SyncSignature) 694 w.params(sig.Params()) 695 w.params(sig.Results()) 696 w.Bool(sig.Variadic()) 697} 698 699func (w *writer) params(typ *types2.Tuple) { 700 w.Sync(pkgbits.SyncParams) 701 w.Len(typ.Len()) 702 for i := 0; i < typ.Len(); i++ { 703 w.param(typ.At(i)) 704 } 705} 706 707func (w *writer) param(param *types2.Var) { 708 w.Sync(pkgbits.SyncParam) 709 w.pos(param) 710 w.localIdent(param) 711 w.typ(param.Type()) 712} 713 714// @@@ Objects 715 716// obj writes a use of the given object into the bitstream. 717// 718// If obj is a generic object, then explicits are the explicit type 719// arguments used to instantiate it (i.e., used to substitute the 720// object's own declared type parameters). 721func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) { 722 w.objInfo(w.p.objInstIdx(obj, explicits, w.dict)) 723} 724 725// objInfo writes a use of the given encoded object into the 726// bitstream. 727func (w *writer) objInfo(info objInfo) { 728 w.Sync(pkgbits.SyncObject) 729 w.Bool(false) // TODO(mdempsky): Remove; was derived func inst. 730 w.Reloc(pkgbits.RelocObj, info.idx) 731 732 w.Len(len(info.explicits)) 733 for _, info := range info.explicits { 734 w.typInfo(info) 735 } 736} 737 738// objInstIdx returns the indices for an object and a corresponding 739// list of type arguments used to instantiate it, adding them to the 740// export data as needed. 741func (pw *pkgWriter) objInstIdx(obj types2.Object, explicits *types2.TypeList, dict *writerDict) objInfo { 742 explicitInfos := make([]typeInfo, explicits.Len()) 743 for i := range explicitInfos { 744 explicitInfos[i] = pw.typIdx(explicits.At(i), dict) 745 } 746 return objInfo{idx: pw.objIdx(obj), explicits: explicitInfos} 747} 748 749// objIdx returns the index for the given Object, adding it to the 750// export data as needed. 751func (pw *pkgWriter) objIdx(obj types2.Object) pkgbits.Index { 752 // TODO(mdempsky): Validate that obj is a global object (or a local 753 // defined type, which we hoist to global scope anyway). 754 755 if idx, ok := pw.objsIdx[obj]; ok { 756 return idx 757 } 758 759 dict := &writerDict{ 760 derivedIdx: make(map[types2.Type]pkgbits.Index), 761 } 762 763 if isDefinedType(obj) && obj.Pkg() == pw.curpkg { 764 decl, ok := pw.typDecls[obj.(*types2.TypeName)] 765 assert(ok) 766 dict.implicits = decl.implicits 767 } 768 769 // We encode objects into 4 elements across different sections, all 770 // sharing the same index: 771 // 772 // - RelocName has just the object's qualified name (i.e., 773 // Object.Pkg and Object.Name) and the CodeObj indicating what 774 // specific type of Object it is (Var, Func, etc). 775 // 776 // - RelocObj has the remaining public details about the object, 777 // relevant to go/types importers. 778 // 779 // - RelocObjExt has additional private details about the object, 780 // which are only relevant to cmd/compile itself. This is 781 // separated from RelocObj so that go/types importers are 782 // unaffected by internal compiler changes. 783 // 784 // - RelocObjDict has public details about the object's type 785 // parameters and derived type's used by the object. This is 786 // separated to facilitate the eventual introduction of 787 // shape-based stenciling. 788 // 789 // TODO(mdempsky): Re-evaluate whether RelocName still makes sense 790 // to keep separate from RelocObj. 791 792 w := pw.newWriter(pkgbits.RelocObj, pkgbits.SyncObject1) 793 wext := pw.newWriter(pkgbits.RelocObjExt, pkgbits.SyncObject1) 794 wname := pw.newWriter(pkgbits.RelocName, pkgbits.SyncObject1) 795 wdict := pw.newWriter(pkgbits.RelocObjDict, pkgbits.SyncObject1) 796 797 pw.objsIdx[obj] = w.Idx // break cycles 798 assert(wext.Idx == w.Idx) 799 assert(wname.Idx == w.Idx) 800 assert(wdict.Idx == w.Idx) 801 802 w.dict = dict 803 wext.dict = dict 804 805 code := w.doObj(wext, obj) 806 w.Flush() 807 wext.Flush() 808 809 wname.qualifiedIdent(obj) 810 wname.Code(code) 811 wname.Flush() 812 813 wdict.objDict(obj, w.dict) 814 wdict.Flush() 815 816 return w.Idx 817} 818 819// doObj writes the RelocObj definition for obj to w, and the 820// RelocObjExt definition to wext. 821func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj { 822 if obj.Pkg() != w.p.curpkg { 823 return pkgbits.ObjStub 824 } 825 826 switch obj := obj.(type) { 827 default: 828 w.p.unexpected("object", obj) 829 panic("unreachable") 830 831 case *types2.Const: 832 w.pos(obj) 833 w.typ(obj.Type()) 834 w.Value(obj.Val()) 835 return pkgbits.ObjConst 836 837 case *types2.Func: 838 decl, ok := w.p.funDecls[obj] 839 assert(ok) 840 sig := obj.Type().(*types2.Signature) 841 842 w.pos(obj) 843 w.typeParamNames(sig.TypeParams()) 844 w.signature(sig) 845 w.pos(decl) 846 wext.funcExt(obj) 847 return pkgbits.ObjFunc 848 849 case *types2.TypeName: 850 if obj.IsAlias() { 851 w.pos(obj) 852 t := obj.Type() 853 if alias, ok := t.(*types2.Alias); ok { // materialized alias 854 t = alias.Rhs() 855 } 856 w.typ(t) 857 return pkgbits.ObjAlias 858 } 859 860 named := obj.Type().(*types2.Named) 861 assert(named.TypeArgs() == nil) 862 863 w.pos(obj) 864 w.typeParamNames(named.TypeParams()) 865 wext.typeExt(obj) 866 w.typ(named.Underlying()) 867 868 w.Len(named.NumMethods()) 869 for i := 0; i < named.NumMethods(); i++ { 870 w.method(wext, named.Method(i)) 871 } 872 873 return pkgbits.ObjType 874 875 case *types2.Var: 876 w.pos(obj) 877 w.typ(obj.Type()) 878 wext.varExt(obj) 879 return pkgbits.ObjVar 880 } 881} 882 883// objDict writes the dictionary needed for reading the given object. 884func (w *writer) objDict(obj types2.Object, dict *writerDict) { 885 // TODO(mdempsky): Split objDict into multiple entries? reader.go 886 // doesn't care about the type parameter bounds, and reader2.go 887 // doesn't care about referenced functions. 888 889 w.dict = dict // TODO(mdempsky): This is a bit sketchy. 890 891 w.Len(len(dict.implicits)) 892 893 tparams := objTypeParams(obj) 894 ntparams := tparams.Len() 895 w.Len(ntparams) 896 for i := 0; i < ntparams; i++ { 897 w.typ(tparams.At(i).Constraint()) 898 } 899 900 nderived := len(dict.derived) 901 w.Len(nderived) 902 for _, typ := range dict.derived { 903 w.Reloc(pkgbits.RelocType, typ.idx) 904 w.Bool(typ.needed) 905 } 906 907 // Write runtime dictionary information. 908 // 909 // N.B., the go/types importer reads up to the section, but doesn't 910 // read any further, so it's safe to change. (See TODO above.) 911 912 // For each type parameter, write out whether the constraint is a 913 // basic interface. This is used to determine how aggressively we 914 // can shape corresponding type arguments. 915 // 916 // This is somewhat redundant with writing out the full type 917 // parameter constraints above, but the compiler currently skips 918 // over those. Also, we don't care about the *declared* constraints, 919 // but how the type parameters are actually *used*. E.g., if a type 920 // parameter is constrained to `int | uint` but then never used in 921 // arithmetic/conversions/etc, we could shape those together. 922 for _, implicit := range dict.implicits { 923 w.Bool(implicit.Underlying().(*types2.Interface).IsMethodSet()) 924 } 925 for i := 0; i < ntparams; i++ { 926 tparam := tparams.At(i) 927 w.Bool(tparam.Underlying().(*types2.Interface).IsMethodSet()) 928 } 929 930 w.Len(len(dict.typeParamMethodExprs)) 931 for _, info := range dict.typeParamMethodExprs { 932 w.Len(info.typeParamIdx) 933 w.selectorInfo(info.methodInfo) 934 } 935 936 w.Len(len(dict.subdicts)) 937 for _, info := range dict.subdicts { 938 w.objInfo(info) 939 } 940 941 w.Len(len(dict.rtypes)) 942 for _, info := range dict.rtypes { 943 w.typInfo(info) 944 } 945 946 w.Len(len(dict.itabs)) 947 for _, info := range dict.itabs { 948 w.typInfo(info.typ) 949 w.typInfo(info.iface) 950 } 951 952 assert(len(dict.derived) == nderived) 953} 954 955func (w *writer) typeParamNames(tparams *types2.TypeParamList) { 956 w.Sync(pkgbits.SyncTypeParamNames) 957 958 ntparams := tparams.Len() 959 for i := 0; i < ntparams; i++ { 960 tparam := tparams.At(i).Obj() 961 w.pos(tparam) 962 w.localIdent(tparam) 963 } 964} 965 966func (w *writer) method(wext *writer, meth *types2.Func) { 967 decl, ok := w.p.funDecls[meth] 968 assert(ok) 969 sig := meth.Type().(*types2.Signature) 970 971 w.Sync(pkgbits.SyncMethod) 972 w.pos(meth) 973 w.selector(meth) 974 w.typeParamNames(sig.RecvTypeParams()) 975 w.param(sig.Recv()) 976 w.signature(sig) 977 978 w.pos(decl) // XXX: Hack to workaround linker limitations. 979 wext.funcExt(meth) 980} 981 982// qualifiedIdent writes out the name of an object declared at package 983// scope. (For now, it's also used to refer to local defined types.) 984func (w *writer) qualifiedIdent(obj types2.Object) { 985 w.Sync(pkgbits.SyncSym) 986 987 name := obj.Name() 988 if isDefinedType(obj) && obj.Pkg() == w.p.curpkg { 989 decl, ok := w.p.typDecls[obj.(*types2.TypeName)] 990 assert(ok) 991 if decl.gen != 0 { 992 // For local defined types, we embed a scope-disambiguation 993 // number directly into their name. types.SplitVargenSuffix then 994 // knows to look for this. 995 // 996 // TODO(mdempsky): Find a better solution; this is terrible. 997 name = fmt.Sprintf("%s·%v", name, decl.gen) 998 } 999 } 1000 1001 w.pkg(obj.Pkg()) 1002 w.String(name) 1003} 1004 1005// TODO(mdempsky): We should be able to omit pkg from both localIdent 1006// and selector, because they should always be known from context. 1007// However, past frustrations with this optimization in iexport make 1008// me a little nervous to try it again. 1009 1010// localIdent writes the name of a locally declared object (i.e., 1011// objects that can only be accessed by non-qualified name, within the 1012// context of a particular function). 1013func (w *writer) localIdent(obj types2.Object) { 1014 assert(!isGlobal(obj)) 1015 w.Sync(pkgbits.SyncLocalIdent) 1016 w.pkg(obj.Pkg()) 1017 w.String(obj.Name()) 1018} 1019 1020// selector writes the name of a field or method (i.e., objects that 1021// can only be accessed using selector expressions). 1022func (w *writer) selector(obj types2.Object) { 1023 w.selectorInfo(w.p.selectorIdx(obj)) 1024} 1025 1026func (w *writer) selectorInfo(info selectorInfo) { 1027 w.Sync(pkgbits.SyncSelector) 1028 w.pkgRef(info.pkgIdx) 1029 w.StringRef(info.nameIdx) 1030} 1031 1032func (pw *pkgWriter) selectorIdx(obj types2.Object) selectorInfo { 1033 pkgIdx := pw.pkgIdx(obj.Pkg()) 1034 nameIdx := pw.StringIdx(obj.Name()) 1035 return selectorInfo{pkgIdx: pkgIdx, nameIdx: nameIdx} 1036} 1037 1038// @@@ Compiler extensions 1039 1040func (w *writer) funcExt(obj *types2.Func) { 1041 decl, ok := w.p.funDecls[obj] 1042 assert(ok) 1043 1044 // TODO(mdempsky): Extend these pragma validation flags to account 1045 // for generics. E.g., linkname probably doesn't make sense at 1046 // least. 1047 1048 pragma := asPragmaFlag(decl.Pragma) 1049 if pragma&ir.Systemstack != 0 && pragma&ir.Nosplit != 0 { 1050 w.p.errorf(decl, "go:nosplit and go:systemstack cannot be combined") 1051 } 1052 wi := asWasmImport(decl.Pragma) 1053 1054 if decl.Body != nil { 1055 if pragma&ir.Noescape != 0 { 1056 w.p.errorf(decl, "can only use //go:noescape with external func implementations") 1057 } 1058 if wi != nil { 1059 w.p.errorf(decl, "can only use //go:wasmimport with external func implementations") 1060 } 1061 if (pragma&ir.UintptrKeepAlive != 0 && pragma&ir.UintptrEscapes == 0) && pragma&ir.Nosplit == 0 { 1062 // Stack growth can't handle uintptr arguments that may 1063 // be pointers (as we don't know which are pointers 1064 // when creating the stack map). Thus uintptrkeepalive 1065 // functions (and all transitive callees) must be 1066 // nosplit. 1067 // 1068 // N.B. uintptrescapes implies uintptrkeepalive but it 1069 // is OK since the arguments must escape to the heap. 1070 // 1071 // TODO(prattmic): Add recursive nosplit check of callees. 1072 // TODO(prattmic): Functions with no body (i.e., 1073 // assembly) must also be nosplit, but we can't check 1074 // that here. 1075 w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit") 1076 } 1077 } else { 1078 if base.Flag.Complete || decl.Name.Value == "init" { 1079 // Linknamed functions are allowed to have no body. Hopefully 1080 // the linkname target has a body. See issue 23311. 1081 // Wasmimport functions are also allowed to have no body. 1082 if _, ok := w.p.linknames[obj]; !ok && wi == nil { 1083 w.p.errorf(decl, "missing function body") 1084 } 1085 } 1086 } 1087 1088 sig, block := obj.Type().(*types2.Signature), decl.Body 1089 body, closureVars := w.p.bodyIdx(sig, block, w.dict) 1090 if len(closureVars) > 0 { 1091 fmt.Fprintln(os.Stderr, "CLOSURE", closureVars) 1092 } 1093 assert(len(closureVars) == 0) 1094 1095 w.Sync(pkgbits.SyncFuncExt) 1096 w.pragmaFlag(pragma) 1097 w.linkname(obj) 1098 1099 if buildcfg.GOARCH == "wasm" { 1100 if wi != nil { 1101 w.String(wi.Module) 1102 w.String(wi.Name) 1103 } else { 1104 w.String("") 1105 w.String("") 1106 } 1107 } 1108 1109 w.Bool(false) // stub extension 1110 w.Reloc(pkgbits.RelocBody, body) 1111 w.Sync(pkgbits.SyncEOF) 1112} 1113 1114func (w *writer) typeExt(obj *types2.TypeName) { 1115 decl, ok := w.p.typDecls[obj] 1116 assert(ok) 1117 1118 w.Sync(pkgbits.SyncTypeExt) 1119 1120 w.pragmaFlag(asPragmaFlag(decl.Pragma)) 1121 1122 // No LSym.SymIdx info yet. 1123 w.Int64(-1) 1124 w.Int64(-1) 1125} 1126 1127func (w *writer) varExt(obj *types2.Var) { 1128 w.Sync(pkgbits.SyncVarExt) 1129 w.linkname(obj) 1130} 1131 1132func (w *writer) linkname(obj types2.Object) { 1133 w.Sync(pkgbits.SyncLinkname) 1134 w.Int64(-1) 1135 w.String(w.p.linknames[obj]) 1136} 1137 1138func (w *writer) pragmaFlag(p ir.PragmaFlag) { 1139 w.Sync(pkgbits.SyncPragma) 1140 w.Int(int(p)) 1141} 1142 1143// @@@ Function bodies 1144 1145// bodyIdx returns the index for the given function body (specified by 1146// block), adding it to the export data 1147func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx pkgbits.Index, closureVars []posVar) { 1148 w := pw.newWriter(pkgbits.RelocBody, pkgbits.SyncFuncBody) 1149 w.sig = sig 1150 w.dict = dict 1151 1152 w.declareParams(sig) 1153 if w.Bool(block != nil) { 1154 w.stmts(block.List) 1155 w.pos(block.Rbrace) 1156 } 1157 1158 return w.Flush(), w.closureVars 1159} 1160 1161func (w *writer) declareParams(sig *types2.Signature) { 1162 addLocals := func(params *types2.Tuple) { 1163 for i := 0; i < params.Len(); i++ { 1164 w.addLocal(params.At(i)) 1165 } 1166 } 1167 1168 if recv := sig.Recv(); recv != nil { 1169 w.addLocal(recv) 1170 } 1171 addLocals(sig.Params()) 1172 addLocals(sig.Results()) 1173} 1174 1175// addLocal records the declaration of a new local variable. 1176func (w *writer) addLocal(obj *types2.Var) { 1177 idx := len(w.localsIdx) 1178 1179 w.Sync(pkgbits.SyncAddLocal) 1180 if w.p.SyncMarkers() { 1181 w.Int(idx) 1182 } 1183 w.varDictIndex(obj) 1184 1185 if w.localsIdx == nil { 1186 w.localsIdx = make(map[*types2.Var]int) 1187 } 1188 w.localsIdx[obj] = idx 1189} 1190 1191// useLocal writes a reference to the given local or free variable 1192// into the bitstream. 1193func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) { 1194 w.Sync(pkgbits.SyncUseObjLocal) 1195 1196 if idx, ok := w.localsIdx[obj]; w.Bool(ok) { 1197 w.Len(idx) 1198 return 1199 } 1200 1201 idx, ok := w.closureVarsIdx[obj] 1202 if !ok { 1203 if w.closureVarsIdx == nil { 1204 w.closureVarsIdx = make(map[*types2.Var]int) 1205 } 1206 idx = len(w.closureVars) 1207 w.closureVars = append(w.closureVars, posVar{pos, obj}) 1208 w.closureVarsIdx[obj] = idx 1209 } 1210 w.Len(idx) 1211} 1212 1213func (w *writer) openScope(pos syntax.Pos) { 1214 w.Sync(pkgbits.SyncOpenScope) 1215 w.pos(pos) 1216} 1217 1218func (w *writer) closeScope(pos syntax.Pos) { 1219 w.Sync(pkgbits.SyncCloseScope) 1220 w.pos(pos) 1221 w.closeAnotherScope() 1222} 1223 1224func (w *writer) closeAnotherScope() { 1225 w.Sync(pkgbits.SyncCloseAnotherScope) 1226} 1227 1228// @@@ Statements 1229 1230// stmt writes the given statement into the function body bitstream. 1231func (w *writer) stmt(stmt syntax.Stmt) { 1232 var stmts []syntax.Stmt 1233 if stmt != nil { 1234 stmts = []syntax.Stmt{stmt} 1235 } 1236 w.stmts(stmts) 1237} 1238 1239func (w *writer) stmts(stmts []syntax.Stmt) { 1240 dead := false 1241 w.Sync(pkgbits.SyncStmts) 1242 var lastLabel = -1 1243 for i, stmt := range stmts { 1244 if _, ok := stmt.(*syntax.LabeledStmt); ok { 1245 lastLabel = i 1246 } 1247 } 1248 for i, stmt := range stmts { 1249 if dead && i > lastLabel { 1250 // Any statements after a terminating and last label statement are safe to omit. 1251 // Otherwise, code after label statement may refer to dead stmts between terminating 1252 // and label statement, see issue #65593. 1253 if _, ok := stmt.(*syntax.LabeledStmt); !ok { 1254 continue 1255 } 1256 } 1257 w.stmt1(stmt) 1258 dead = w.p.terminates(stmt) 1259 } 1260 w.Code(stmtEnd) 1261 w.Sync(pkgbits.SyncStmtsEnd) 1262} 1263 1264func (w *writer) stmt1(stmt syntax.Stmt) { 1265 switch stmt := stmt.(type) { 1266 default: 1267 w.p.unexpected("statement", stmt) 1268 1269 case nil, *syntax.EmptyStmt: 1270 return 1271 1272 case *syntax.AssignStmt: 1273 switch { 1274 case stmt.Rhs == nil: 1275 w.Code(stmtIncDec) 1276 w.op(binOps[stmt.Op]) 1277 w.expr(stmt.Lhs) 1278 w.pos(stmt) 1279 1280 case stmt.Op != 0 && stmt.Op != syntax.Def: 1281 w.Code(stmtAssignOp) 1282 w.op(binOps[stmt.Op]) 1283 w.expr(stmt.Lhs) 1284 w.pos(stmt) 1285 1286 var typ types2.Type 1287 if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr { 1288 typ = w.p.typeOf(stmt.Lhs) 1289 } 1290 w.implicitConvExpr(typ, stmt.Rhs) 1291 1292 default: 1293 w.assignStmt(stmt, stmt.Lhs, stmt.Rhs) 1294 } 1295 1296 case *syntax.BlockStmt: 1297 w.Code(stmtBlock) 1298 w.blockStmt(stmt) 1299 1300 case *syntax.BranchStmt: 1301 w.Code(stmtBranch) 1302 w.pos(stmt) 1303 w.op(branchOps[stmt.Tok]) 1304 w.optLabel(stmt.Label) 1305 1306 case *syntax.CallStmt: 1307 w.Code(stmtCall) 1308 w.pos(stmt) 1309 w.op(callOps[stmt.Tok]) 1310 w.expr(stmt.Call) 1311 if stmt.Tok == syntax.Defer { 1312 w.optExpr(stmt.DeferAt) 1313 } 1314 1315 case *syntax.DeclStmt: 1316 for _, decl := range stmt.DeclList { 1317 w.declStmt(decl) 1318 } 1319 1320 case *syntax.ExprStmt: 1321 w.Code(stmtExpr) 1322 w.expr(stmt.X) 1323 1324 case *syntax.ForStmt: 1325 w.Code(stmtFor) 1326 w.forStmt(stmt) 1327 1328 case *syntax.IfStmt: 1329 w.Code(stmtIf) 1330 w.ifStmt(stmt) 1331 1332 case *syntax.LabeledStmt: 1333 w.Code(stmtLabel) 1334 w.pos(stmt) 1335 w.label(stmt.Label) 1336 w.stmt1(stmt.Stmt) 1337 1338 case *syntax.ReturnStmt: 1339 w.Code(stmtReturn) 1340 w.pos(stmt) 1341 1342 resultTypes := w.sig.Results() 1343 dstType := func(i int) types2.Type { 1344 return resultTypes.At(i).Type() 1345 } 1346 w.multiExpr(stmt, dstType, syntax.UnpackListExpr(stmt.Results)) 1347 1348 case *syntax.SelectStmt: 1349 w.Code(stmtSelect) 1350 w.selectStmt(stmt) 1351 1352 case *syntax.SendStmt: 1353 chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan) 1354 1355 w.Code(stmtSend) 1356 w.pos(stmt) 1357 w.expr(stmt.Chan) 1358 w.implicitConvExpr(chanType.Elem(), stmt.Value) 1359 1360 case *syntax.SwitchStmt: 1361 w.Code(stmtSwitch) 1362 w.switchStmt(stmt) 1363 } 1364} 1365 1366func (w *writer) assignList(expr syntax.Expr) { 1367 exprs := syntax.UnpackListExpr(expr) 1368 w.Len(len(exprs)) 1369 1370 for _, expr := range exprs { 1371 w.assign(expr) 1372 } 1373} 1374 1375func (w *writer) assign(expr syntax.Expr) { 1376 expr = syntax.Unparen(expr) 1377 1378 if name, ok := expr.(*syntax.Name); ok { 1379 if name.Value == "_" { 1380 w.Code(assignBlank) 1381 return 1382 } 1383 1384 if obj, ok := w.p.info.Defs[name]; ok { 1385 obj := obj.(*types2.Var) 1386 1387 w.Code(assignDef) 1388 w.pos(obj) 1389 w.localIdent(obj) 1390 w.typ(obj.Type()) 1391 1392 // TODO(mdempsky): Minimize locals index size by deferring 1393 // this until the variables actually come into scope. 1394 w.addLocal(obj) 1395 return 1396 } 1397 } 1398 1399 w.Code(assignExpr) 1400 w.expr(expr) 1401} 1402 1403func (w *writer) declStmt(decl syntax.Decl) { 1404 switch decl := decl.(type) { 1405 default: 1406 w.p.unexpected("declaration", decl) 1407 1408 case *syntax.ConstDecl, *syntax.TypeDecl: 1409 1410 case *syntax.VarDecl: 1411 w.assignStmt(decl, namesAsExpr(decl.NameList), decl.Values) 1412 } 1413} 1414 1415// assignStmt writes out an assignment for "lhs = rhs". 1416func (w *writer) assignStmt(pos poser, lhs0, rhs0 syntax.Expr) { 1417 lhs := syntax.UnpackListExpr(lhs0) 1418 rhs := syntax.UnpackListExpr(rhs0) 1419 1420 w.Code(stmtAssign) 1421 w.pos(pos) 1422 1423 // As if w.assignList(lhs0). 1424 w.Len(len(lhs)) 1425 for _, expr := range lhs { 1426 w.assign(expr) 1427 } 1428 1429 dstType := func(i int) types2.Type { 1430 dst := lhs[i] 1431 1432 // Finding dstType is somewhat involved, because for VarDecl 1433 // statements, the Names are only added to the info.{Defs,Uses} 1434 // maps, not to info.Types. 1435 if name, ok := syntax.Unparen(dst).(*syntax.Name); ok { 1436 if name.Value == "_" { 1437 return nil // ok: no implicit conversion 1438 } else if def, ok := w.p.info.Defs[name].(*types2.Var); ok { 1439 return def.Type() 1440 } else if use, ok := w.p.info.Uses[name].(*types2.Var); ok { 1441 return use.Type() 1442 } else { 1443 w.p.fatalf(dst, "cannot find type of destination object: %v", dst) 1444 } 1445 } 1446 1447 return w.p.typeOf(dst) 1448 } 1449 1450 w.multiExpr(pos, dstType, rhs) 1451} 1452 1453func (w *writer) blockStmt(stmt *syntax.BlockStmt) { 1454 w.Sync(pkgbits.SyncBlockStmt) 1455 w.openScope(stmt.Pos()) 1456 w.stmts(stmt.List) 1457 w.closeScope(stmt.Rbrace) 1458} 1459 1460func (w *writer) forStmt(stmt *syntax.ForStmt) { 1461 w.Sync(pkgbits.SyncForStmt) 1462 w.openScope(stmt.Pos()) 1463 1464 if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) { 1465 w.pos(rang) 1466 w.assignList(rang.Lhs) 1467 w.expr(rang.X) 1468 1469 xtyp := w.p.typeOf(rang.X) 1470 if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap { 1471 w.rtype(xtyp) 1472 } 1473 { 1474 lhs := syntax.UnpackListExpr(rang.Lhs) 1475 assign := func(i int, src types2.Type) { 1476 if i >= len(lhs) { 1477 return 1478 } 1479 dst := syntax.Unparen(lhs[i]) 1480 if name, ok := dst.(*syntax.Name); ok && name.Value == "_" { 1481 return 1482 } 1483 1484 var dstType types2.Type 1485 if rang.Def { 1486 // For `:=` assignments, the LHS names only appear in Defs, 1487 // not Types (as used by typeOf). 1488 dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type() 1489 } else { 1490 dstType = w.p.typeOf(dst) 1491 } 1492 1493 w.convRTTI(src, dstType) 1494 } 1495 1496 keyType, valueType := types2.RangeKeyVal(w.p.typeOf(rang.X)) 1497 assign(0, keyType) 1498 assign(1, valueType) 1499 } 1500 1501 } else { 1502 if stmt.Cond != nil && w.p.staticBool(&stmt.Cond) < 0 { // always false 1503 stmt.Post = nil 1504 stmt.Body.List = nil 1505 } 1506 1507 w.pos(stmt) 1508 w.stmt(stmt.Init) 1509 w.optExpr(stmt.Cond) 1510 w.stmt(stmt.Post) 1511 } 1512 1513 w.blockStmt(stmt.Body) 1514 w.Bool(w.distinctVars(stmt)) 1515 w.closeAnotherScope() 1516} 1517 1518func (w *writer) distinctVars(stmt *syntax.ForStmt) bool { 1519 lv := base.Debug.LoopVar 1520 fileVersion := w.p.info.FileVersions[stmt.Pos().Base()] 1521 is122 := fileVersion == "" || version.Compare(fileVersion, "go1.22") >= 0 1522 1523 // Turning off loopvar for 1.22 is only possible with loopvarhash=qn 1524 // 1525 // Debug.LoopVar values to be preserved for 1.21 compatibility are 1 and 2, 1526 // which are also set (=1) by GOEXPERIMENT=loopvar. The knobs for turning on 1527 // the new, unshared, loopvar behavior apply to versions less than 1.21 because 1528 // (1) 1.21 also did that and (2) this is believed to be the likely use case; 1529 // anyone checking to see if it affects their code will just run the GOEXPERIMENT 1530 // but will not also update all their go.mod files to 1.21. 1531 // 1532 // -gcflags=-d=loopvar=3 enables logging for 1.22 but does not turn loopvar on for <= 1.21. 1533 1534 return is122 || lv > 0 && lv != 3 1535} 1536 1537func (w *writer) ifStmt(stmt *syntax.IfStmt) { 1538 cond := w.p.staticBool(&stmt.Cond) 1539 1540 w.Sync(pkgbits.SyncIfStmt) 1541 w.openScope(stmt.Pos()) 1542 w.pos(stmt) 1543 w.stmt(stmt.Init) 1544 w.expr(stmt.Cond) 1545 w.Int(cond) 1546 if cond >= 0 { 1547 w.blockStmt(stmt.Then) 1548 } else { 1549 w.pos(stmt.Then.Rbrace) 1550 } 1551 if cond <= 0 { 1552 w.stmt(stmt.Else) 1553 } 1554 w.closeAnotherScope() 1555} 1556 1557func (w *writer) selectStmt(stmt *syntax.SelectStmt) { 1558 w.Sync(pkgbits.SyncSelectStmt) 1559 1560 w.pos(stmt) 1561 w.Len(len(stmt.Body)) 1562 for i, clause := range stmt.Body { 1563 if i > 0 { 1564 w.closeScope(clause.Pos()) 1565 } 1566 w.openScope(clause.Pos()) 1567 1568 w.pos(clause) 1569 w.stmt(clause.Comm) 1570 w.stmts(clause.Body) 1571 } 1572 if len(stmt.Body) > 0 { 1573 w.closeScope(stmt.Rbrace) 1574 } 1575} 1576 1577func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { 1578 w.Sync(pkgbits.SyncSwitchStmt) 1579 1580 w.openScope(stmt.Pos()) 1581 w.pos(stmt) 1582 w.stmt(stmt.Init) 1583 1584 var iface, tagType types2.Type 1585 var tagTypeIsChan bool 1586 if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) { 1587 iface = w.p.typeOf(guard.X) 1588 1589 w.pos(guard) 1590 if tag := guard.Lhs; w.Bool(tag != nil) { 1591 w.pos(tag) 1592 1593 // Like w.localIdent, but we don't have a types2.Object. 1594 w.Sync(pkgbits.SyncLocalIdent) 1595 w.pkg(w.p.curpkg) 1596 w.String(tag.Value) 1597 } 1598 w.expr(guard.X) 1599 } else { 1600 tag := stmt.Tag 1601 1602 var tagValue constant.Value 1603 if tag != nil { 1604 tv := w.p.typeAndValue(tag) 1605 tagType = tv.Type 1606 tagValue = tv.Value 1607 _, tagTypeIsChan = tagType.Underlying().(*types2.Chan) 1608 } else { 1609 tagType = types2.Typ[types2.Bool] 1610 tagValue = constant.MakeBool(true) 1611 } 1612 1613 if tagValue != nil { 1614 // If the switch tag has a constant value, look for a case 1615 // clause that we always branch to. 1616 func() { 1617 var target *syntax.CaseClause 1618 Outer: 1619 for _, clause := range stmt.Body { 1620 if clause.Cases == nil { 1621 target = clause 1622 } 1623 for _, cas := range syntax.UnpackListExpr(clause.Cases) { 1624 tv := w.p.typeAndValue(cas) 1625 if tv.Value == nil { 1626 return // non-constant case; give up 1627 } 1628 if constant.Compare(tagValue, token.EQL, tv.Value) { 1629 target = clause 1630 break Outer 1631 } 1632 } 1633 } 1634 // We've found the target clause, if any. 1635 1636 if target != nil { 1637 if hasFallthrough(target.Body) { 1638 return // fallthrough is tricky; give up 1639 } 1640 1641 // Rewrite as single "default" case. 1642 target.Cases = nil 1643 stmt.Body = []*syntax.CaseClause{target} 1644 } else { 1645 stmt.Body = nil 1646 } 1647 1648 // Clear switch tag (i.e., replace with implicit "true"). 1649 tag = nil 1650 stmt.Tag = nil 1651 tagType = types2.Typ[types2.Bool] 1652 }() 1653 } 1654 1655 // Walk is going to emit comparisons between the tag value and 1656 // each case expression, and we want these comparisons to always 1657 // have the same type. If there are any case values that can't be 1658 // converted to the tag value's type, then convert everything to 1659 // `any` instead. 1660 // 1661 // Except that we need to keep comparisons of channel values from 1662 // being wrapped in any(). See issue #67190. 1663 1664 if !tagTypeIsChan { 1665 Outer: 1666 for _, clause := range stmt.Body { 1667 for _, cas := range syntax.UnpackListExpr(clause.Cases) { 1668 if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) { 1669 tagType = types2.NewInterfaceType(nil, nil) 1670 break Outer 1671 } 1672 } 1673 } 1674 } 1675 1676 if w.Bool(tag != nil) { 1677 w.implicitConvExpr(tagType, tag) 1678 } 1679 } 1680 1681 w.Len(len(stmt.Body)) 1682 for i, clause := range stmt.Body { 1683 if i > 0 { 1684 w.closeScope(clause.Pos()) 1685 } 1686 w.openScope(clause.Pos()) 1687 1688 w.pos(clause) 1689 1690 cases := syntax.UnpackListExpr(clause.Cases) 1691 if iface != nil { 1692 w.Len(len(cases)) 1693 for _, cas := range cases { 1694 if w.Bool(isNil(w.p, cas)) { 1695 continue 1696 } 1697 w.exprType(iface, cas) 1698 } 1699 } else { 1700 // As if w.exprList(clause.Cases), 1701 // but with implicit conversions to tagType. 1702 1703 w.Sync(pkgbits.SyncExprList) 1704 w.Sync(pkgbits.SyncExprs) 1705 w.Len(len(cases)) 1706 for _, cas := range cases { 1707 typ := tagType 1708 if tagTypeIsChan { 1709 typ = nil 1710 } 1711 w.implicitConvExpr(typ, cas) 1712 } 1713 } 1714 1715 if obj, ok := w.p.info.Implicits[clause]; ok { 1716 // TODO(mdempsky): These pos details are quirkish, but also 1717 // necessary so the variable's position is correct for DWARF 1718 // scope assignment later. It would probably be better for us to 1719 // instead just set the variable's DWARF scoping info earlier so 1720 // we can give it the correct position information. 1721 pos := clause.Pos() 1722 if typs := syntax.UnpackListExpr(clause.Cases); len(typs) != 0 { 1723 pos = typeExprEndPos(typs[len(typs)-1]) 1724 } 1725 w.pos(pos) 1726 1727 obj := obj.(*types2.Var) 1728 w.typ(obj.Type()) 1729 w.addLocal(obj) 1730 } 1731 1732 w.stmts(clause.Body) 1733 } 1734 if len(stmt.Body) > 0 { 1735 w.closeScope(stmt.Rbrace) 1736 } 1737 1738 w.closeScope(stmt.Rbrace) 1739} 1740 1741func (w *writer) label(label *syntax.Name) { 1742 w.Sync(pkgbits.SyncLabel) 1743 1744 // TODO(mdempsky): Replace label strings with dense indices. 1745 w.String(label.Value) 1746} 1747 1748func (w *writer) optLabel(label *syntax.Name) { 1749 w.Sync(pkgbits.SyncOptLabel) 1750 if w.Bool(label != nil) { 1751 w.label(label) 1752 } 1753} 1754 1755// @@@ Expressions 1756 1757// expr writes the given expression into the function body bitstream. 1758func (w *writer) expr(expr syntax.Expr) { 1759 base.Assertf(expr != nil, "missing expression") 1760 1761 expr = syntax.Unparen(expr) // skip parens; unneeded after typecheck 1762 1763 obj, inst := lookupObj(w.p, expr) 1764 targs := inst.TypeArgs 1765 1766 if tv, ok := w.p.maybeTypeAndValue(expr); ok { 1767 if tv.IsRuntimeHelper() { 1768 if pkg := obj.Pkg(); pkg != nil && pkg.Name() == "runtime" { 1769 objName := obj.Name() 1770 w.Code(exprRuntimeBuiltin) 1771 w.String(objName) 1772 return 1773 } 1774 } 1775 1776 if tv.IsType() { 1777 w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr)) 1778 } 1779 1780 if tv.Value != nil { 1781 w.Code(exprConst) 1782 w.pos(expr) 1783 typ := idealType(tv) 1784 assert(typ != nil) 1785 w.typ(typ) 1786 w.Value(tv.Value) 1787 return 1788 } 1789 1790 if _, isNil := obj.(*types2.Nil); isNil { 1791 w.Code(exprZero) 1792 w.pos(expr) 1793 w.typ(tv.Type) 1794 return 1795 } 1796 1797 // With shape types (and particular pointer shaping), we may have 1798 // an expression of type "go.shape.*uint8", but need to reshape it 1799 // to another shape-identical type to allow use in field 1800 // selection, indexing, etc. 1801 if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) { 1802 w.Code(exprReshape) 1803 w.typ(typ) 1804 // fallthrough 1805 } 1806 } 1807 1808 if obj != nil { 1809 if targs.Len() != 0 { 1810 obj := obj.(*types2.Func) 1811 1812 w.Code(exprFuncInst) 1813 w.pos(expr) 1814 w.funcInst(obj, targs) 1815 return 1816 } 1817 1818 if isGlobal(obj) { 1819 w.Code(exprGlobal) 1820 w.obj(obj, nil) 1821 return 1822 } 1823 1824 obj := obj.(*types2.Var) 1825 assert(!obj.IsField()) 1826 1827 w.Code(exprLocal) 1828 w.useLocal(expr.Pos(), obj) 1829 return 1830 } 1831 1832 switch expr := expr.(type) { 1833 default: 1834 w.p.unexpected("expression", expr) 1835 1836 case *syntax.CompositeLit: 1837 w.Code(exprCompLit) 1838 w.compLit(expr) 1839 1840 case *syntax.FuncLit: 1841 w.Code(exprFuncLit) 1842 w.funcLit(expr) 1843 1844 case *syntax.SelectorExpr: 1845 sel, ok := w.p.info.Selections[expr] 1846 assert(ok) 1847 1848 switch sel.Kind() { 1849 default: 1850 w.p.fatalf(expr, "unexpected selection kind: %v", sel.Kind()) 1851 1852 case types2.FieldVal: 1853 w.Code(exprFieldVal) 1854 w.expr(expr.X) 1855 w.pos(expr) 1856 w.selector(sel.Obj()) 1857 1858 case types2.MethodVal: 1859 w.Code(exprMethodVal) 1860 typ := w.recvExpr(expr, sel) 1861 w.pos(expr) 1862 w.methodExpr(expr, typ, sel) 1863 1864 case types2.MethodExpr: 1865 w.Code(exprMethodExpr) 1866 1867 tv := w.p.typeAndValue(expr.X) 1868 assert(tv.IsType()) 1869 1870 index := sel.Index() 1871 implicits := index[:len(index)-1] 1872 1873 typ := tv.Type 1874 w.typ(typ) 1875 1876 w.Len(len(implicits)) 1877 for _, ix := range implicits { 1878 w.Len(ix) 1879 typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() 1880 } 1881 1882 recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() 1883 if w.Bool(isPtrTo(typ, recv)) { // need deref 1884 typ = recv 1885 } else if w.Bool(isPtrTo(recv, typ)) { // need addr 1886 typ = recv 1887 } 1888 1889 w.pos(expr) 1890 w.methodExpr(expr, typ, sel) 1891 } 1892 1893 case *syntax.IndexExpr: 1894 _ = w.p.typeOf(expr.Index) // ensure this is an index expression, not an instantiation 1895 1896 xtyp := w.p.typeOf(expr.X) 1897 1898 var keyType types2.Type 1899 if mapType, ok := types2.CoreType(xtyp).(*types2.Map); ok { 1900 keyType = mapType.Key() 1901 } 1902 1903 w.Code(exprIndex) 1904 w.expr(expr.X) 1905 w.pos(expr) 1906 w.implicitConvExpr(keyType, expr.Index) 1907 if keyType != nil { 1908 w.rtype(xtyp) 1909 } 1910 1911 case *syntax.SliceExpr: 1912 w.Code(exprSlice) 1913 w.expr(expr.X) 1914 w.pos(expr) 1915 for _, n := range &expr.Index { 1916 w.optExpr(n) 1917 } 1918 1919 case *syntax.AssertExpr: 1920 iface := w.p.typeOf(expr.X) 1921 1922 w.Code(exprAssert) 1923 w.expr(expr.X) 1924 w.pos(expr) 1925 w.exprType(iface, expr.Type) 1926 w.rtype(iface) 1927 1928 case *syntax.Operation: 1929 if expr.Y == nil { 1930 w.Code(exprUnaryOp) 1931 w.op(unOps[expr.Op]) 1932 w.pos(expr) 1933 w.expr(expr.X) 1934 break 1935 } 1936 1937 var commonType types2.Type 1938 switch expr.Op { 1939 case syntax.Shl, syntax.Shr: 1940 // ok: operands are allowed to have different types 1941 default: 1942 xtyp := w.p.typeOf(expr.X) 1943 ytyp := w.p.typeOf(expr.Y) 1944 switch { 1945 case types2.AssignableTo(xtyp, ytyp): 1946 commonType = ytyp 1947 case types2.AssignableTo(ytyp, xtyp): 1948 commonType = xtyp 1949 default: 1950 w.p.fatalf(expr, "failed to find common type between %v and %v", xtyp, ytyp) 1951 } 1952 } 1953 1954 w.Code(exprBinaryOp) 1955 w.op(binOps[expr.Op]) 1956 w.implicitConvExpr(commonType, expr.X) 1957 w.pos(expr) 1958 w.implicitConvExpr(commonType, expr.Y) 1959 1960 case *syntax.CallExpr: 1961 tv := w.p.typeAndValue(expr.Fun) 1962 if tv.IsType() { 1963 assert(len(expr.ArgList) == 1) 1964 assert(!expr.HasDots) 1965 w.convertExpr(tv.Type, expr.ArgList[0], false) 1966 break 1967 } 1968 1969 var rtype types2.Type 1970 if tv.IsBuiltin() { 1971 switch obj, _ := lookupObj(w.p, syntax.Unparen(expr.Fun)); obj.Name() { 1972 case "make": 1973 assert(len(expr.ArgList) >= 1) 1974 assert(!expr.HasDots) 1975 1976 w.Code(exprMake) 1977 w.pos(expr) 1978 w.exprType(nil, expr.ArgList[0]) 1979 w.exprs(expr.ArgList[1:]) 1980 1981 typ := w.p.typeOf(expr) 1982 switch coreType := types2.CoreType(typ).(type) { 1983 default: 1984 w.p.fatalf(expr, "unexpected core type: %v", coreType) 1985 case *types2.Chan: 1986 w.rtype(typ) 1987 case *types2.Map: 1988 w.rtype(typ) 1989 case *types2.Slice: 1990 w.rtype(sliceElem(typ)) 1991 } 1992 1993 return 1994 1995 case "new": 1996 assert(len(expr.ArgList) == 1) 1997 assert(!expr.HasDots) 1998 1999 w.Code(exprNew) 2000 w.pos(expr) 2001 w.exprType(nil, expr.ArgList[0]) 2002 return 2003 2004 case "Sizeof": 2005 assert(len(expr.ArgList) == 1) 2006 assert(!expr.HasDots) 2007 2008 w.Code(exprSizeof) 2009 w.pos(expr) 2010 w.typ(w.p.typeOf(expr.ArgList[0])) 2011 return 2012 2013 case "Alignof": 2014 assert(len(expr.ArgList) == 1) 2015 assert(!expr.HasDots) 2016 2017 w.Code(exprAlignof) 2018 w.pos(expr) 2019 w.typ(w.p.typeOf(expr.ArgList[0])) 2020 return 2021 2022 case "Offsetof": 2023 assert(len(expr.ArgList) == 1) 2024 assert(!expr.HasDots) 2025 selector := syntax.Unparen(expr.ArgList[0]).(*syntax.SelectorExpr) 2026 index := w.p.info.Selections[selector].Index() 2027 2028 w.Code(exprOffsetof) 2029 w.pos(expr) 2030 w.typ(deref2(w.p.typeOf(selector.X))) 2031 w.Len(len(index) - 1) 2032 for _, idx := range index { 2033 w.Len(idx) 2034 } 2035 return 2036 2037 case "append": 2038 rtype = sliceElem(w.p.typeOf(expr)) 2039 case "copy": 2040 typ := w.p.typeOf(expr.ArgList[0]) 2041 if tuple, ok := typ.(*types2.Tuple); ok { // "copy(g())" 2042 typ = tuple.At(0).Type() 2043 } 2044 rtype = sliceElem(typ) 2045 case "delete": 2046 typ := w.p.typeOf(expr.ArgList[0]) 2047 if tuple, ok := typ.(*types2.Tuple); ok { // "delete(g())" 2048 typ = tuple.At(0).Type() 2049 } 2050 rtype = typ 2051 case "Slice": 2052 rtype = sliceElem(w.p.typeOf(expr)) 2053 } 2054 } 2055 2056 writeFunExpr := func() { 2057 fun := syntax.Unparen(expr.Fun) 2058 2059 if selector, ok := fun.(*syntax.SelectorExpr); ok { 2060 if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal { 2061 w.Bool(true) // method call 2062 typ := w.recvExpr(selector, sel) 2063 w.methodExpr(selector, typ, sel) 2064 return 2065 } 2066 } 2067 2068 w.Bool(false) // not a method call (i.e., normal function call) 2069 2070 if obj, inst := lookupObj(w.p, fun); w.Bool(obj != nil && inst.TypeArgs.Len() != 0) { 2071 obj := obj.(*types2.Func) 2072 2073 w.pos(fun) 2074 w.funcInst(obj, inst.TypeArgs) 2075 return 2076 } 2077 2078 w.expr(fun) 2079 } 2080 2081 sigType := types2.CoreType(tv.Type).(*types2.Signature) 2082 paramTypes := sigType.Params() 2083 2084 w.Code(exprCall) 2085 writeFunExpr() 2086 w.pos(expr) 2087 2088 paramType := func(i int) types2.Type { 2089 if sigType.Variadic() && !expr.HasDots && i >= paramTypes.Len()-1 { 2090 return paramTypes.At(paramTypes.Len() - 1).Type().(*types2.Slice).Elem() 2091 } 2092 return paramTypes.At(i).Type() 2093 } 2094 2095 w.multiExpr(expr, paramType, expr.ArgList) 2096 w.Bool(expr.HasDots) 2097 if rtype != nil { 2098 w.rtype(rtype) 2099 } 2100 } 2101} 2102 2103func sliceElem(typ types2.Type) types2.Type { 2104 return types2.CoreType(typ).(*types2.Slice).Elem() 2105} 2106 2107func (w *writer) optExpr(expr syntax.Expr) { 2108 if w.Bool(expr != nil) { 2109 w.expr(expr) 2110 } 2111} 2112 2113// recvExpr writes out expr.X, but handles any implicit addressing, 2114// dereferencing, and field selections appropriate for the method 2115// selection. 2116func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) types2.Type { 2117 index := sel.Index() 2118 implicits := index[:len(index)-1] 2119 2120 w.Code(exprRecv) 2121 w.expr(expr.X) 2122 w.pos(expr) 2123 w.Len(len(implicits)) 2124 2125 typ := w.p.typeOf(expr.X) 2126 for _, ix := range implicits { 2127 typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() 2128 w.Len(ix) 2129 } 2130 2131 recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() 2132 if w.Bool(isPtrTo(typ, recv)) { // needs deref 2133 typ = recv 2134 } else if w.Bool(isPtrTo(recv, typ)) { // needs addr 2135 typ = recv 2136 } 2137 2138 return typ 2139} 2140 2141// funcInst writes a reference to an instantiated function. 2142func (w *writer) funcInst(obj *types2.Func, targs *types2.TypeList) { 2143 info := w.p.objInstIdx(obj, targs, w.dict) 2144 2145 // Type arguments list contains derived types; we can emit a static 2146 // call to the shaped function, but need to dynamically compute the 2147 // runtime dictionary pointer. 2148 if w.Bool(info.anyDerived()) { 2149 w.Len(w.dict.subdictIdx(info)) 2150 return 2151 } 2152 2153 // Type arguments list is statically known; we can emit a static 2154 // call with a statically reference to the respective runtime 2155 // dictionary. 2156 w.objInfo(info) 2157} 2158 2159// methodExpr writes out a reference to the method selected by 2160// expr. sel should be the corresponding types2.Selection, and recv 2161// the type produced after any implicit addressing, dereferencing, and 2162// field selection. (Note: recv might differ from sel.Obj()'s receiver 2163// parameter in the case of interface types, and is needed for 2164// handling type parameter methods.) 2165func (w *writer) methodExpr(expr *syntax.SelectorExpr, recv types2.Type, sel *types2.Selection) { 2166 fun := sel.Obj().(*types2.Func) 2167 sig := fun.Type().(*types2.Signature) 2168 2169 w.typ(recv) 2170 w.typ(sig) 2171 w.pos(expr) 2172 w.selector(fun) 2173 2174 // Method on a type parameter. These require an indirect call 2175 // through the current function's runtime dictionary. 2176 if typeParam, ok := types2.Unalias(recv).(*types2.TypeParam); w.Bool(ok) { 2177 typeParamIdx := w.dict.typeParamIndex(typeParam) 2178 methodInfo := w.p.selectorIdx(fun) 2179 2180 w.Len(w.dict.typeParamMethodExprIdx(typeParamIdx, methodInfo)) 2181 return 2182 } 2183 2184 if isInterface(recv) != isInterface(sig.Recv().Type()) { 2185 w.p.fatalf(expr, "isInterface inconsistency: %v and %v", recv, sig.Recv().Type()) 2186 } 2187 2188 if !isInterface(recv) { 2189 if named, ok := types2.Unalias(deref2(recv)).(*types2.Named); ok { 2190 obj, targs := splitNamed(named) 2191 info := w.p.objInstIdx(obj, targs, w.dict) 2192 2193 // Method on a derived receiver type. These can be handled by a 2194 // static call to the shaped method, but require dynamically 2195 // looking up the appropriate dictionary argument in the current 2196 // function's runtime dictionary. 2197 if w.p.hasImplicitTypeParams(obj) || info.anyDerived() { 2198 w.Bool(true) // dynamic subdictionary 2199 w.Len(w.dict.subdictIdx(info)) 2200 return 2201 } 2202 2203 // Method on a fully known receiver type. These can be handled 2204 // by a static call to the shaped method, and with a static 2205 // reference to the receiver type's dictionary. 2206 if targs.Len() != 0 { 2207 w.Bool(false) // no dynamic subdictionary 2208 w.Bool(true) // static dictionary 2209 w.objInfo(info) 2210 return 2211 } 2212 } 2213 } 2214 2215 w.Bool(false) // no dynamic subdictionary 2216 w.Bool(false) // no static dictionary 2217} 2218 2219// multiExpr writes a sequence of expressions, where the i'th value is 2220// implicitly converted to dstType(i). It also handles when exprs is a 2221// single, multi-valued expression (e.g., the multi-valued argument in 2222// an f(g()) call, or the RHS operand in a comma-ok assignment). 2223func (w *writer) multiExpr(pos poser, dstType func(int) types2.Type, exprs []syntax.Expr) { 2224 w.Sync(pkgbits.SyncMultiExpr) 2225 2226 if len(exprs) == 1 { 2227 expr := exprs[0] 2228 if tuple, ok := w.p.typeOf(expr).(*types2.Tuple); ok { 2229 assert(tuple.Len() > 1) 2230 w.Bool(true) // N:1 assignment 2231 w.pos(pos) 2232 w.expr(expr) 2233 2234 w.Len(tuple.Len()) 2235 for i := 0; i < tuple.Len(); i++ { 2236 src := tuple.At(i).Type() 2237 // TODO(mdempsky): Investigate not writing src here. I think 2238 // the reader should be able to infer it from expr anyway. 2239 w.typ(src) 2240 if dst := dstType(i); w.Bool(dst != nil && !types2.Identical(src, dst)) { 2241 if src == nil || dst == nil { 2242 w.p.fatalf(pos, "src is %v, dst is %v", src, dst) 2243 } 2244 if !types2.AssignableTo(src, dst) { 2245 w.p.fatalf(pos, "%v is not assignable to %v", src, dst) 2246 } 2247 w.typ(dst) 2248 w.convRTTI(src, dst) 2249 } 2250 } 2251 return 2252 } 2253 } 2254 2255 w.Bool(false) // N:N assignment 2256 w.Len(len(exprs)) 2257 for i, expr := range exprs { 2258 w.implicitConvExpr(dstType(i), expr) 2259 } 2260} 2261 2262// implicitConvExpr is like expr, but if dst is non-nil and different 2263// from expr's type, then an implicit conversion operation is inserted 2264// at expr's position. 2265func (w *writer) implicitConvExpr(dst types2.Type, expr syntax.Expr) { 2266 w.convertExpr(dst, expr, true) 2267} 2268 2269func (w *writer) convertExpr(dst types2.Type, expr syntax.Expr, implicit bool) { 2270 src := w.p.typeOf(expr) 2271 2272 // Omit implicit no-op conversions. 2273 identical := dst == nil || types2.Identical(src, dst) 2274 if implicit && identical { 2275 w.expr(expr) 2276 return 2277 } 2278 2279 if implicit && !types2.AssignableTo(src, dst) { 2280 w.p.fatalf(expr, "%v is not assignable to %v", src, dst) 2281 } 2282 2283 w.Code(exprConvert) 2284 w.Bool(implicit) 2285 w.typ(dst) 2286 w.pos(expr) 2287 w.convRTTI(src, dst) 2288 w.Bool(isTypeParam(dst)) 2289 w.Bool(identical) 2290 w.expr(expr) 2291} 2292 2293func (w *writer) compLit(lit *syntax.CompositeLit) { 2294 typ := w.p.typeOf(lit) 2295 2296 w.Sync(pkgbits.SyncCompLit) 2297 w.pos(lit) 2298 w.typ(typ) 2299 2300 if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok { 2301 typ = ptr.Elem() 2302 } 2303 var keyType, elemType types2.Type 2304 var structType *types2.Struct 2305 switch typ0 := typ; typ := types2.CoreType(typ).(type) { 2306 default: 2307 w.p.fatalf(lit, "unexpected composite literal type: %v", typ) 2308 case *types2.Array: 2309 elemType = typ.Elem() 2310 case *types2.Map: 2311 w.rtype(typ0) 2312 keyType, elemType = typ.Key(), typ.Elem() 2313 case *types2.Slice: 2314 elemType = typ.Elem() 2315 case *types2.Struct: 2316 structType = typ 2317 } 2318 2319 w.Len(len(lit.ElemList)) 2320 for i, elem := range lit.ElemList { 2321 elemType := elemType 2322 if structType != nil { 2323 if kv, ok := elem.(*syntax.KeyValueExpr); ok { 2324 // use position of expr.Key rather than of elem (which has position of ':') 2325 w.pos(kv.Key) 2326 i = fieldIndex(w.p.info, structType, kv.Key.(*syntax.Name)) 2327 elem = kv.Value 2328 } else { 2329 w.pos(elem) 2330 } 2331 elemType = structType.Field(i).Type() 2332 w.Len(i) 2333 } else { 2334 if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) { 2335 // use position of expr.Key rather than of elem (which has position of ':') 2336 w.pos(kv.Key) 2337 w.implicitConvExpr(keyType, kv.Key) 2338 elem = kv.Value 2339 } 2340 } 2341 w.implicitConvExpr(elemType, elem) 2342 } 2343} 2344 2345func (w *writer) funcLit(expr *syntax.FuncLit) { 2346 sig := w.p.typeOf(expr).(*types2.Signature) 2347 2348 body, closureVars := w.p.bodyIdx(sig, expr.Body, w.dict) 2349 2350 w.Sync(pkgbits.SyncFuncLit) 2351 w.pos(expr) 2352 w.signature(sig) 2353 w.Bool(w.p.rangeFuncBodyClosures[expr]) 2354 2355 w.Len(len(closureVars)) 2356 for _, cv := range closureVars { 2357 w.pos(cv.pos) 2358 w.useLocal(cv.pos, cv.var_) 2359 } 2360 2361 w.Reloc(pkgbits.RelocBody, body) 2362} 2363 2364type posVar struct { 2365 pos syntax.Pos 2366 var_ *types2.Var 2367} 2368 2369func (p posVar) String() string { 2370 return p.pos.String() + ":" + p.var_.String() 2371} 2372 2373func (w *writer) exprList(expr syntax.Expr) { 2374 w.Sync(pkgbits.SyncExprList) 2375 w.exprs(syntax.UnpackListExpr(expr)) 2376} 2377 2378func (w *writer) exprs(exprs []syntax.Expr) { 2379 w.Sync(pkgbits.SyncExprs) 2380 w.Len(len(exprs)) 2381 for _, expr := range exprs { 2382 w.expr(expr) 2383 } 2384} 2385 2386// rtype writes information so that the reader can construct an 2387// expression of type *runtime._type representing typ. 2388func (w *writer) rtype(typ types2.Type) { 2389 typ = types2.Default(typ) 2390 2391 info := w.p.typIdx(typ, w.dict) 2392 w.rtypeInfo(info) 2393} 2394 2395func (w *writer) rtypeInfo(info typeInfo) { 2396 w.Sync(pkgbits.SyncRType) 2397 2398 if w.Bool(info.derived) { 2399 w.Len(w.dict.rtypeIdx(info)) 2400 } else { 2401 w.typInfo(info) 2402 } 2403} 2404 2405// varDictIndex writes out information for populating DictIndex for 2406// the ir.Name that will represent obj. 2407func (w *writer) varDictIndex(obj *types2.Var) { 2408 info := w.p.typIdx(obj.Type(), w.dict) 2409 if w.Bool(info.derived) { 2410 w.Len(w.dict.rtypeIdx(info)) 2411 } 2412} 2413 2414// isUntyped reports whether typ is an untyped type. 2415func isUntyped(typ types2.Type) bool { 2416 // Note: types2.Unalias is unnecessary here, since untyped types can't be aliased. 2417 basic, ok := typ.(*types2.Basic) 2418 return ok && basic.Info()&types2.IsUntyped != 0 2419} 2420 2421// isTuple reports whether typ is a tuple type. 2422func isTuple(typ types2.Type) bool { 2423 // Note: types2.Unalias is unnecessary here, since tuple types can't be aliased. 2424 _, ok := typ.(*types2.Tuple) 2425 return ok 2426} 2427 2428func (w *writer) itab(typ, iface types2.Type) { 2429 typ = types2.Default(typ) 2430 iface = types2.Default(iface) 2431 2432 typInfo := w.p.typIdx(typ, w.dict) 2433 ifaceInfo := w.p.typIdx(iface, w.dict) 2434 2435 w.rtypeInfo(typInfo) 2436 w.rtypeInfo(ifaceInfo) 2437 if w.Bool(typInfo.derived || ifaceInfo.derived) { 2438 w.Len(w.dict.itabIdx(typInfo, ifaceInfo)) 2439 } 2440} 2441 2442// convRTTI writes information so that the reader can construct 2443// expressions for converting from src to dst. 2444func (w *writer) convRTTI(src, dst types2.Type) { 2445 w.Sync(pkgbits.SyncConvRTTI) 2446 w.itab(src, dst) 2447} 2448 2449func (w *writer) exprType(iface types2.Type, typ syntax.Expr) { 2450 base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface) 2451 2452 tv := w.p.typeAndValue(typ) 2453 assert(tv.IsType()) 2454 2455 w.Sync(pkgbits.SyncExprType) 2456 w.pos(typ) 2457 2458 if w.Bool(iface != nil && !iface.Underlying().(*types2.Interface).Empty()) { 2459 w.itab(tv.Type, iface) 2460 } else { 2461 w.rtype(tv.Type) 2462 2463 info := w.p.typIdx(tv.Type, w.dict) 2464 w.Bool(info.derived) 2465 } 2466} 2467 2468// isInterface reports whether typ is known to be an interface type. 2469// If typ is a type parameter, then isInterface reports an internal 2470// compiler error instead. 2471func isInterface(typ types2.Type) bool { 2472 if _, ok := types2.Unalias(typ).(*types2.TypeParam); ok { 2473 // typ is a type parameter and may be instantiated as either a 2474 // concrete or interface type, so the writer can't depend on 2475 // knowing this. 2476 base.Fatalf("%v is a type parameter", typ) 2477 } 2478 2479 _, ok := typ.Underlying().(*types2.Interface) 2480 return ok 2481} 2482 2483// op writes an Op into the bitstream. 2484func (w *writer) op(op ir.Op) { 2485 // TODO(mdempsky): Remove in favor of explicit codes? Would make 2486 // export data more stable against internal refactorings, but low 2487 // priority at the moment. 2488 assert(op != 0) 2489 w.Sync(pkgbits.SyncOp) 2490 w.Len(int(op)) 2491} 2492 2493// @@@ Package initialization 2494 2495// Caution: This code is still clumsy, because toolstash -cmp is 2496// particularly sensitive to it. 2497 2498type typeDeclGen struct { 2499 *syntax.TypeDecl 2500 gen int 2501 2502 // Implicit type parameters in scope at this type declaration. 2503 implicits []*types2.TypeParam 2504} 2505 2506type fileImports struct { 2507 importedEmbed, importedUnsafe bool 2508} 2509 2510// declCollector is a visitor type that collects compiler-needed 2511// information about declarations that types2 doesn't track. 2512// 2513// Notably, it maps declared types and functions back to their 2514// declaration statement, keeps track of implicit type parameters, and 2515// assigns unique type "generation" numbers to local defined types. 2516type declCollector struct { 2517 pw *pkgWriter 2518 typegen *int 2519 file *fileImports 2520 withinFunc bool 2521 implicits []*types2.TypeParam 2522} 2523 2524func (c *declCollector) withTParams(obj types2.Object) *declCollector { 2525 tparams := objTypeParams(obj) 2526 n := tparams.Len() 2527 if n == 0 { 2528 return c 2529 } 2530 2531 copy := *c 2532 copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)] 2533 for i := 0; i < n; i++ { 2534 copy.implicits = append(copy.implicits, tparams.At(i)) 2535 } 2536 return © 2537} 2538 2539func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { 2540 pw := c.pw 2541 2542 switch n := n.(type) { 2543 case *syntax.File: 2544 pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false) 2545 2546 case *syntax.ImportDecl: 2547 pw.checkPragmas(n.Pragma, 0, false) 2548 2549 switch pw.info.PkgNameOf(n).Imported().Path() { 2550 case "embed": 2551 c.file.importedEmbed = true 2552 case "unsafe": 2553 c.file.importedUnsafe = true 2554 } 2555 2556 case *syntax.ConstDecl: 2557 pw.checkPragmas(n.Pragma, 0, false) 2558 2559 case *syntax.FuncDecl: 2560 pw.checkPragmas(n.Pragma, funcPragmas, false) 2561 2562 obj := pw.info.Defs[n.Name].(*types2.Func) 2563 pw.funDecls[obj] = n 2564 2565 return c.withTParams(obj) 2566 2567 case *syntax.TypeDecl: 2568 obj := pw.info.Defs[n.Name].(*types2.TypeName) 2569 d := typeDeclGen{TypeDecl: n, implicits: c.implicits} 2570 2571 if n.Alias { 2572 pw.checkPragmas(n.Pragma, 0, false) 2573 } else { 2574 pw.checkPragmas(n.Pragma, 0, false) 2575 2576 // Assign a unique ID to function-scoped defined types. 2577 if c.withinFunc { 2578 *c.typegen++ 2579 d.gen = *c.typegen 2580 } 2581 } 2582 2583 pw.typDecls[obj] = d 2584 2585 // TODO(mdempsky): Omit? Not strictly necessary; only matters for 2586 // type declarations within function literals within parameterized 2587 // type declarations, but types2 the function literals will be 2588 // constant folded away. 2589 return c.withTParams(obj) 2590 2591 case *syntax.VarDecl: 2592 pw.checkPragmas(n.Pragma, 0, true) 2593 2594 if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 { 2595 if err := checkEmbed(n, c.file.importedEmbed, c.withinFunc); err != nil { 2596 pw.errorf(p.Embeds[0].Pos, "%s", err) 2597 } 2598 } 2599 2600 case *syntax.BlockStmt: 2601 if !c.withinFunc { 2602 copy := *c 2603 copy.withinFunc = true 2604 return © 2605 } 2606 } 2607 2608 return c 2609} 2610 2611func (pw *pkgWriter) collectDecls(noders []*noder) { 2612 var typegen int 2613 for _, p := range noders { 2614 var file fileImports 2615 2616 syntax.Walk(p.file, &declCollector{ 2617 pw: pw, 2618 typegen: &typegen, 2619 file: &file, 2620 }) 2621 2622 pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...) 2623 2624 for _, l := range p.linknames { 2625 if !file.importedUnsafe { 2626 pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") 2627 continue 2628 } 2629 if strings.Contains(l.remote, "[") && strings.Contains(l.remote, "]") { 2630 pw.errorf(l.pos, "//go:linkname reference of an instantiation is not allowed") 2631 continue 2632 } 2633 2634 switch obj := pw.curpkg.Scope().Lookup(l.local).(type) { 2635 case *types2.Func, *types2.Var: 2636 if _, ok := pw.linknames[obj]; !ok { 2637 pw.linknames[obj] = l.remote 2638 } else { 2639 pw.errorf(l.pos, "duplicate //go:linkname for %s", l.local) 2640 } 2641 2642 default: 2643 if types.AllowsGoVersion(1, 18) { 2644 pw.errorf(l.pos, "//go:linkname must refer to declared function or variable") 2645 } 2646 } 2647 } 2648 } 2649} 2650 2651func (pw *pkgWriter) checkPragmas(p syntax.Pragma, allowed ir.PragmaFlag, embedOK bool) { 2652 if p == nil { 2653 return 2654 } 2655 pragma := p.(*pragmas) 2656 2657 for _, pos := range pragma.Pos { 2658 if pos.Flag&^allowed != 0 { 2659 pw.errorf(pos.Pos, "misplaced compiler directive") 2660 } 2661 } 2662 2663 if !embedOK { 2664 for _, e := range pragma.Embeds { 2665 pw.errorf(e.Pos, "misplaced go:embed directive") 2666 } 2667 } 2668} 2669 2670func (w *writer) pkgInit(noders []*noder) { 2671 w.Len(len(w.p.cgoPragmas)) 2672 for _, cgoPragma := range w.p.cgoPragmas { 2673 w.Strings(cgoPragma) 2674 } 2675 2676 w.pkgInitOrder() 2677 2678 w.Sync(pkgbits.SyncDecls) 2679 for _, p := range noders { 2680 for _, decl := range p.file.DeclList { 2681 w.pkgDecl(decl) 2682 } 2683 } 2684 w.Code(declEnd) 2685 2686 w.Sync(pkgbits.SyncEOF) 2687} 2688 2689func (w *writer) pkgInitOrder() { 2690 // TODO(mdempsky): Write as a function body instead? 2691 w.Len(len(w.p.info.InitOrder)) 2692 for _, init := range w.p.info.InitOrder { 2693 w.Len(len(init.Lhs)) 2694 for _, v := range init.Lhs { 2695 w.obj(v, nil) 2696 } 2697 w.expr(init.Rhs) 2698 } 2699} 2700 2701func (w *writer) pkgDecl(decl syntax.Decl) { 2702 switch decl := decl.(type) { 2703 default: 2704 w.p.unexpected("declaration", decl) 2705 2706 case *syntax.ImportDecl: 2707 2708 case *syntax.ConstDecl: 2709 w.Code(declOther) 2710 w.pkgObjs(decl.NameList...) 2711 2712 case *syntax.FuncDecl: 2713 if decl.Name.Value == "_" { 2714 break // skip blank functions 2715 } 2716 2717 obj := w.p.info.Defs[decl.Name].(*types2.Func) 2718 sig := obj.Type().(*types2.Signature) 2719 2720 if sig.RecvTypeParams() != nil || sig.TypeParams() != nil { 2721 break // skip generic functions 2722 } 2723 2724 if recv := sig.Recv(); recv != nil { 2725 w.Code(declMethod) 2726 w.typ(recvBase(recv)) 2727 w.selector(obj) 2728 break 2729 } 2730 2731 w.Code(declFunc) 2732 w.pkgObjs(decl.Name) 2733 2734 case *syntax.TypeDecl: 2735 if len(decl.TParamList) != 0 { 2736 break // skip generic type decls 2737 } 2738 2739 if decl.Name.Value == "_" { 2740 break // skip blank type decls 2741 } 2742 2743 name := w.p.info.Defs[decl.Name].(*types2.TypeName) 2744 // Skip type declarations for interfaces that are only usable as 2745 // type parameter bounds. 2746 if iface, ok := name.Type().Underlying().(*types2.Interface); ok && !iface.IsMethodSet() { 2747 break 2748 } 2749 2750 w.Code(declOther) 2751 w.pkgObjs(decl.Name) 2752 2753 case *syntax.VarDecl: 2754 w.Code(declVar) 2755 w.pkgObjs(decl.NameList...) 2756 2757 var embeds []pragmaEmbed 2758 if p, ok := decl.Pragma.(*pragmas); ok { 2759 embeds = p.Embeds 2760 } 2761 w.Len(len(embeds)) 2762 for _, embed := range embeds { 2763 w.pos(embed.Pos) 2764 w.Strings(embed.Patterns) 2765 } 2766 } 2767} 2768 2769func (w *writer) pkgObjs(names ...*syntax.Name) { 2770 w.Sync(pkgbits.SyncDeclNames) 2771 w.Len(len(names)) 2772 2773 for _, name := range names { 2774 obj, ok := w.p.info.Defs[name] 2775 assert(ok) 2776 2777 w.Sync(pkgbits.SyncDeclName) 2778 w.obj(obj, nil) 2779 } 2780} 2781 2782// @@@ Helpers 2783 2784// staticBool analyzes a boolean expression and reports whether it's 2785// always true (positive result), always false (negative result), or 2786// unknown (zero). 2787// 2788// It also simplifies the expression while preserving semantics, if 2789// possible. 2790func (pw *pkgWriter) staticBool(ep *syntax.Expr) int { 2791 if val := pw.typeAndValue(*ep).Value; val != nil { 2792 if constant.BoolVal(val) { 2793 return +1 2794 } else { 2795 return -1 2796 } 2797 } 2798 2799 if e, ok := (*ep).(*syntax.Operation); ok { 2800 switch e.Op { 2801 case syntax.Not: 2802 return pw.staticBool(&e.X) 2803 2804 case syntax.AndAnd: 2805 x := pw.staticBool(&e.X) 2806 if x < 0 { 2807 *ep = e.X 2808 return x 2809 } 2810 2811 y := pw.staticBool(&e.Y) 2812 if x > 0 || y < 0 { 2813 if pw.typeAndValue(e.X).Value != nil { 2814 *ep = e.Y 2815 } 2816 return y 2817 } 2818 2819 case syntax.OrOr: 2820 x := pw.staticBool(&e.X) 2821 if x > 0 { 2822 *ep = e.X 2823 return x 2824 } 2825 2826 y := pw.staticBool(&e.Y) 2827 if x < 0 || y > 0 { 2828 if pw.typeAndValue(e.X).Value != nil { 2829 *ep = e.Y 2830 } 2831 return y 2832 } 2833 } 2834 } 2835 2836 return 0 2837} 2838 2839// hasImplicitTypeParams reports whether obj is a defined type with 2840// implicit type parameters (e.g., declared within a generic function 2841// or method). 2842func (pw *pkgWriter) hasImplicitTypeParams(obj *types2.TypeName) bool { 2843 if obj.Pkg() == pw.curpkg { 2844 decl, ok := pw.typDecls[obj] 2845 assert(ok) 2846 if len(decl.implicits) != 0 { 2847 return true 2848 } 2849 } 2850 return false 2851} 2852 2853// isDefinedType reports whether obj is a defined type. 2854func isDefinedType(obj types2.Object) bool { 2855 if obj, ok := obj.(*types2.TypeName); ok { 2856 return !obj.IsAlias() 2857 } 2858 return false 2859} 2860 2861// isGlobal reports whether obj was declared at package scope. 2862// 2863// Caveat: blank objects are not declared. 2864func isGlobal(obj types2.Object) bool { 2865 return obj.Parent() == obj.Pkg().Scope() 2866} 2867 2868// lookupObj returns the object that expr refers to, if any. If expr 2869// is an explicit instantiation of a generic object, then the instance 2870// object is returned as well. 2871func lookupObj(p *pkgWriter, expr syntax.Expr) (obj types2.Object, inst types2.Instance) { 2872 if index, ok := expr.(*syntax.IndexExpr); ok { 2873 args := syntax.UnpackListExpr(index.Index) 2874 if len(args) == 1 { 2875 tv := p.typeAndValue(args[0]) 2876 if tv.IsValue() { 2877 return // normal index expression 2878 } 2879 } 2880 2881 expr = index.X 2882 } 2883 2884 // Strip package qualifier, if present. 2885 if sel, ok := expr.(*syntax.SelectorExpr); ok { 2886 if !isPkgQual(p.info, sel) { 2887 return // normal selector expression 2888 } 2889 expr = sel.Sel 2890 } 2891 2892 if name, ok := expr.(*syntax.Name); ok { 2893 obj = p.info.Uses[name] 2894 inst = p.info.Instances[name] 2895 } 2896 return 2897} 2898 2899// isPkgQual reports whether the given selector expression is a 2900// package-qualified identifier. 2901func isPkgQual(info *types2.Info, sel *syntax.SelectorExpr) bool { 2902 if name, ok := sel.X.(*syntax.Name); ok { 2903 _, isPkgName := info.Uses[name].(*types2.PkgName) 2904 return isPkgName 2905 } 2906 return false 2907} 2908 2909// isNil reports whether expr is a (possibly parenthesized) reference 2910// to the predeclared nil value. 2911func isNil(p *pkgWriter, expr syntax.Expr) bool { 2912 tv := p.typeAndValue(expr) 2913 return tv.IsNil() 2914} 2915 2916// isBuiltin reports whether expr is a (possibly parenthesized) 2917// referenced to the specified built-in function. 2918func (pw *pkgWriter) isBuiltin(expr syntax.Expr, builtin string) bool { 2919 if name, ok := syntax.Unparen(expr).(*syntax.Name); ok && name.Value == builtin { 2920 return pw.typeAndValue(name).IsBuiltin() 2921 } 2922 return false 2923} 2924 2925// recvBase returns the base type for the given receiver parameter. 2926func recvBase(recv *types2.Var) *types2.Named { 2927 typ := types2.Unalias(recv.Type()) 2928 if ptr, ok := typ.(*types2.Pointer); ok { 2929 typ = types2.Unalias(ptr.Elem()) 2930 } 2931 return typ.(*types2.Named) 2932} 2933 2934// namesAsExpr returns a list of names as a syntax.Expr. 2935func namesAsExpr(names []*syntax.Name) syntax.Expr { 2936 if len(names) == 1 { 2937 return names[0] 2938 } 2939 2940 exprs := make([]syntax.Expr, len(names)) 2941 for i, name := range names { 2942 exprs[i] = name 2943 } 2944 return &syntax.ListExpr{ElemList: exprs} 2945} 2946 2947// fieldIndex returns the index of the struct field named by key. 2948func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { 2949 field := info.Uses[key].(*types2.Var) 2950 2951 for i := 0; i < str.NumFields(); i++ { 2952 if str.Field(i) == field { 2953 return i 2954 } 2955 } 2956 2957 panic(fmt.Sprintf("%s: %v is not a field of %v", key.Pos(), field, str)) 2958} 2959 2960// objTypeParams returns the type parameters on the given object. 2961func objTypeParams(obj types2.Object) *types2.TypeParamList { 2962 switch obj := obj.(type) { 2963 case *types2.Func: 2964 sig := obj.Type().(*types2.Signature) 2965 if sig.Recv() != nil { 2966 return sig.RecvTypeParams() 2967 } 2968 return sig.TypeParams() 2969 case *types2.TypeName: 2970 if !obj.IsAlias() { 2971 return obj.Type().(*types2.Named).TypeParams() 2972 } 2973 if alias, ok := obj.Type().(*types2.Alias); ok { 2974 return alias.TypeParams() 2975 } 2976 } 2977 return nil 2978} 2979 2980// splitNamed decomposes a use of a defined type into its original 2981// type definition and the type arguments used to instantiate it. 2982func splitNamed(typ *types2.Named) (*types2.TypeName, *types2.TypeList) { 2983 base.Assertf(typ.TypeParams().Len() == typ.TypeArgs().Len(), "use of uninstantiated type: %v", typ) 2984 2985 orig := typ.Origin() 2986 base.Assertf(orig.TypeArgs() == nil, "origin %v of %v has type arguments", orig, typ) 2987 base.Assertf(typ.Obj() == orig.Obj(), "%v has object %v, but %v has object %v", typ, typ.Obj(), orig, orig.Obj()) 2988 2989 return typ.Obj(), typ.TypeArgs() 2990} 2991 2992// splitAlias is like splitNamed, but for an alias type. 2993func splitAlias(typ *types2.Alias) (*types2.TypeName, *types2.TypeList) { 2994 orig := typ.Origin() 2995 base.Assertf(typ.Obj() == orig.Obj(), "alias type %v has object %v, but %v has object %v", typ, typ.Obj(), orig, orig.Obj()) 2996 2997 return typ.Obj(), typ.TypeArgs() 2998} 2999 3000func asPragmaFlag(p syntax.Pragma) ir.PragmaFlag { 3001 if p == nil { 3002 return 0 3003 } 3004 return p.(*pragmas).Flag 3005} 3006 3007func asWasmImport(p syntax.Pragma) *WasmImport { 3008 if p == nil { 3009 return nil 3010 } 3011 return p.(*pragmas).WasmImport 3012} 3013 3014// isPtrTo reports whether from is the type *to. 3015func isPtrTo(from, to types2.Type) bool { 3016 ptr, ok := types2.Unalias(from).(*types2.Pointer) 3017 return ok && types2.Identical(ptr.Elem(), to) 3018} 3019 3020// hasFallthrough reports whether stmts ends in a fallthrough 3021// statement. 3022func hasFallthrough(stmts []syntax.Stmt) bool { 3023 last, ok := lastNonEmptyStmt(stmts).(*syntax.BranchStmt) 3024 return ok && last.Tok == syntax.Fallthrough 3025} 3026 3027// lastNonEmptyStmt returns the last non-empty statement in list, if 3028// any. 3029func lastNonEmptyStmt(stmts []syntax.Stmt) syntax.Stmt { 3030 for i := len(stmts) - 1; i >= 0; i-- { 3031 stmt := stmts[i] 3032 if _, ok := stmt.(*syntax.EmptyStmt); !ok { 3033 return stmt 3034 } 3035 } 3036 return nil 3037} 3038 3039// terminates reports whether stmt terminates normal control flow 3040// (i.e., does not merely advance to the following statement). 3041func (pw *pkgWriter) terminates(stmt syntax.Stmt) bool { 3042 switch stmt := stmt.(type) { 3043 case *syntax.BranchStmt: 3044 if stmt.Tok == syntax.Goto { 3045 return true 3046 } 3047 case *syntax.ReturnStmt: 3048 return true 3049 case *syntax.ExprStmt: 3050 if call, ok := syntax.Unparen(stmt.X).(*syntax.CallExpr); ok { 3051 if pw.isBuiltin(call.Fun, "panic") { 3052 return true 3053 } 3054 } 3055 3056 // The handling of BlockStmt here is approximate, but it serves to 3057 // allow dead-code elimination for: 3058 // 3059 // if true { 3060 // return x 3061 // } 3062 // unreachable 3063 case *syntax.IfStmt: 3064 cond := pw.staticBool(&stmt.Cond) 3065 return (cond < 0 || pw.terminates(stmt.Then)) && (cond > 0 || pw.terminates(stmt.Else)) 3066 case *syntax.BlockStmt: 3067 return pw.terminates(lastNonEmptyStmt(stmt.List)) 3068 } 3069 3070 return false 3071} 3072