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.
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/ir"
16 "cmd/compile/internal/syntax"
17 "cmd/compile/internal/types"
18 "cmd/compile/internal/types2"
21 // This file implements the Unified IR package writer and defines the
22 // Unified IR export data format.
24 // Low-level coding details (e.g., byte-encoding of individual
25 // primitive values, or handling element bitstreams and
26 // cross-references) are handled by internal/pkgbits, so here we only
27 // concern ourselves with higher-level worries like mapping Go
28 // language constructs into elements.
30 // There are two central types in the writing process: the "writer"
31 // type handles writing out individual elements, while the "pkgWriter"
32 // type keeps track of which elements have already been created.
34 // For each sort of "thing" (e.g., position, package, object, type)
35 // that can be written into the export data, there are generally
36 // several methods that work together:
38 // - writer.thing handles writing out a *use* of a thing, which often
39 // means writing a relocation to that thing's encoded index.
41 // - pkgWriter.thingIdx handles reserving an index for a thing, and
42 // writing out any elements needed for the thing.
44 // - writer.doThing handles writing out the *definition* of a thing,
45 // which in general is a mix of low-level coding primitives (e.g.,
46 // ints and strings) or uses of other things.
48 // A design goal of Unified IR is to have a single, canonical writer
49 // implementation, but multiple reader implementations each tailored
50 // to their respective needs. For example, within cmd/compile's own
51 // backend, inlining is implemented largely by just re-running the
52 // function body reading code.
54 // TODO(mdempsky): Add an importer for Unified IR to the x/tools repo,
55 // and better document the file format boundary between public and
58 // A pkgWriter constructs Unified IR export data from the results of
59 // running the types2 type checker on a Go compilation unit.
60 type pkgWriter struct {
64 curpkg *types2.Package
67 // Indices for previously written syntax and types2 things.
69 posBasesIdx map[*syntax.PosBase]pkgbits.Index
70 pkgsIdx map[*types2.Package]pkgbits.Index
71 typsIdx map[types2.Type]pkgbits.Index
72 objsIdx map[types2.Object]pkgbits.Index
74 // Maps from types2.Objects back to their syntax.Decl.
76 funDecls map[*types2.Func]*syntax.FuncDecl
77 typDecls map[*types2.TypeName]typeDeclGen
79 // linknames maps package-scope objects to their linker symbol name,
80 // if specified by a //go:linkname directive.
81 linknames map[types2.Object]string
83 // cgoPragmas accumulates any //go:cgo_* pragmas that need to be
84 // passed through to cmd/link.
88 // newPkgWriter returns an initialized pkgWriter for the specified
90 func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter {
92 PkgEncoder: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
98 pkgsIdx: make(map[*types2.Package]pkgbits.Index),
99 objsIdx: make(map[types2.Object]pkgbits.Index),
100 typsIdx: make(map[types2.Type]pkgbits.Index),
102 posBasesIdx: make(map[*syntax.PosBase]pkgbits.Index),
104 funDecls: make(map[*types2.Func]*syntax.FuncDecl),
105 typDecls: make(map[*types2.TypeName]typeDeclGen),
107 linknames: make(map[types2.Object]string),
111 // errorf reports a user error about thing p.
112 func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) {
113 base.ErrorfAt(pw.m.pos(p), 0, msg, args...)
116 // fatalf reports an internal compiler error about thing p.
117 func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) {
118 base.FatalfAt(pw.m.pos(p), msg, args...)
121 // unexpected reports a fatal error about a thing of unexpected
123 func (pw *pkgWriter) unexpected(what string, p poser) {
124 pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p)
127 func (pw *pkgWriter) typeAndValue(x syntax.Expr) syntax.TypeAndValue {
128 tv, ok := pw.maybeTypeAndValue(x)
130 pw.fatalf(x, "missing Types entry: %v", syntax.String(x))
135 func (pw *pkgWriter) maybeTypeAndValue(x syntax.Expr) (syntax.TypeAndValue, bool) {
136 tv := x.GetTypeInfo()
138 // If x is a generic function whose type arguments are inferred
139 // from assignment context, then we need to find its inferred type
140 // in Info.Instances instead.
141 if name, ok := x.(*syntax.Name); ok {
142 if inst, ok := pw.info.Instances[name]; ok {
147 return tv, tv.Type != nil
150 // typeOf returns the Type of the given value expression.
151 func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type {
152 tv := pw.typeAndValue(expr)
154 pw.fatalf(expr, "expected value: %v", syntax.String(expr))
159 // A writer provides APIs for writing out an individual element.
165 // sig holds the signature for the current function body, if any.
166 sig *types2.Signature
168 // TODO(mdempsky): We should be able to prune localsIdx whenever a
169 // scope closes, and then maybe we can just use the same map for
170 // storing the TypeParams too (as their TypeName instead).
172 // localsIdx tracks any local variables declared within this
173 // function body. It's unused for writing out non-body things.
174 localsIdx map[*types2.Var]int
176 // closureVars tracks any free variables that are referenced by this
177 // function body. It's unused for writing out non-body things.
179 closureVarsIdx map[*types2.Var]int // index of previously seen free variables
183 // derived tracks whether the type being written out references any
184 // type parameters. It's unused for writing non-type things.
188 // A writerDict tracks types and objects that are used by a declaration.
189 type writerDict struct {
190 implicits []*types2.TypeName
192 // derived is a slice of type indices for computing derived types
193 // (i.e., types that depend on the declaration's type parameters).
194 derived []derivedInfo
196 // derivedIdx maps a Type to its corresponding index within the
197 // derived slice, if present.
198 derivedIdx map[types2.Type]pkgbits.Index
200 // These slices correspond to entries in the runtime dictionary.
201 typeParamMethodExprs []writerMethodExprInfo
207 type itabInfo struct {
212 // typeParamIndex returns the index of the given type parameter within
213 // the dictionary. This may differ from typ.Index() when there are
214 // implicit type parameters due to defined types declared within a
215 // generic function or method.
216 func (dict *writerDict) typeParamIndex(typ *types2.TypeParam) int {
217 for idx, implicit := range dict.implicits {
218 if implicit.Type().(*types2.TypeParam) == typ {
223 return len(dict.implicits) + typ.Index()
226 // A derivedInfo represents a reference to an encoded generic Go type.
227 type derivedInfo struct {
229 needed bool // TODO(mdempsky): Remove.
232 // A typeInfo represents a reference to an encoded Go type.
234 // If derived is true, then the typeInfo represents a generic Go type
235 // that contains type parameters. In this case, idx is an index into
236 // the readerDict.derived{,Types} arrays.
238 // Otherwise, the typeInfo represents a non-generic Go type, and idx
239 // is an index into the reader.typs array instead.
240 type typeInfo struct {
245 // An objInfo represents a reference to an encoded, instantiated (if
246 // applicable) Go object.
247 type objInfo struct {
248 idx pkgbits.Index // index for the generic function declaration
249 explicits []typeInfo // info for the type arguments
252 // A selectorInfo represents a reference to an encoded field or method
253 // name (i.e., objects that can only be accessed using selector
255 type selectorInfo struct {
257 nameIdx pkgbits.Index
260 // anyDerived reports whether any of info's explicit type arguments
261 // are derived types.
262 func (info objInfo) anyDerived() bool {
263 for _, explicit := range info.explicits {
264 if explicit.derived {
271 // equals reports whether info and other represent the same Go object
272 // (i.e., same base object and identical type arguments, if any).
273 func (info objInfo) equals(other objInfo) bool {
274 if info.idx != other.idx {
277 assert(len(info.explicits) == len(other.explicits))
278 for i, targ := range info.explicits {
279 if targ != other.explicits[i] {
286 type writerMethodExprInfo struct {
288 methodInfo selectorInfo
291 // typeParamMethodExprIdx returns the index where the given encoded
292 // method expression function pointer appears within this dictionary's
293 // type parameters method expressions section, adding it if necessary.
294 func (dict *writerDict) typeParamMethodExprIdx(typeParamIdx int, methodInfo selectorInfo) int {
295 newInfo := writerMethodExprInfo{typeParamIdx, methodInfo}
297 for idx, oldInfo := range dict.typeParamMethodExprs {
298 if oldInfo == newInfo {
303 idx := len(dict.typeParamMethodExprs)
304 dict.typeParamMethodExprs = append(dict.typeParamMethodExprs, newInfo)
308 // subdictIdx returns the index where the given encoded object's
309 // runtime dictionary appears within this dictionary's subdictionary
310 // section, adding it if necessary.
311 func (dict *writerDict) subdictIdx(newInfo objInfo) int {
312 for idx, oldInfo := range dict.subdicts {
313 if oldInfo.equals(newInfo) {
318 idx := len(dict.subdicts)
319 dict.subdicts = append(dict.subdicts, newInfo)
323 // rtypeIdx returns the index where the given encoded type's
324 // *runtime._type value appears within this dictionary's rtypes
325 // section, adding it if necessary.
326 func (dict *writerDict) rtypeIdx(newInfo typeInfo) int {
327 for idx, oldInfo := range dict.rtypes {
328 if oldInfo == newInfo {
333 idx := len(dict.rtypes)
334 dict.rtypes = append(dict.rtypes, newInfo)
338 // itabIdx returns the index where the given encoded type pair's
339 // *runtime.itab value appears within this dictionary's itabs section,
340 // adding it if necessary.
341 func (dict *writerDict) itabIdx(typInfo, ifaceInfo typeInfo) int {
342 newInfo := itabInfo{typInfo, ifaceInfo}
344 for idx, oldInfo := range dict.itabs {
345 if oldInfo == newInfo {
350 idx := len(dict.itabs)
351 dict.itabs = append(dict.itabs, newInfo)
355 func (pw *pkgWriter) newWriter(k pkgbits.RelocKind, marker pkgbits.SyncMarker) *writer {
357 Encoder: pw.NewEncoder(k, marker),
364 // pos writes the position of p into the element bitstream.
365 func (w *writer) pos(p poser) {
366 w.Sync(pkgbits.SyncPos)
369 // TODO(mdempsky): Track down the remaining cases here and fix them.
370 if !w.Bool(pos.IsKnown()) {
374 // TODO(mdempsky): Delta encoding.
375 w.posBase(pos.Base())
380 // posBase writes a reference to the given PosBase into the element
382 func (w *writer) posBase(b *syntax.PosBase) {
383 w.Reloc(pkgbits.RelocPosBase, w.p.posBaseIdx(b))
386 // posBaseIdx returns the index for the given PosBase.
387 func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) pkgbits.Index {
388 if idx, ok := pw.posBasesIdx[b]; ok {
392 w := pw.newWriter(pkgbits.RelocPosBase, pkgbits.SyncPosBase)
393 w.p.posBasesIdx[b] = w.Idx
395 w.String(trimFilename(b))
397 if !w.Bool(b.IsFileBase()) {
408 // pkg writes a use of the given Package into the element bitstream.
409 func (w *writer) pkg(pkg *types2.Package) {
410 w.pkgRef(w.p.pkgIdx(pkg))
413 func (w *writer) pkgRef(idx pkgbits.Index) {
414 w.Sync(pkgbits.SyncPkg)
415 w.Reloc(pkgbits.RelocPkg, idx)
418 // pkgIdx returns the index for the given package, adding it to the
419 // package export data if needed.
420 func (pw *pkgWriter) pkgIdx(pkg *types2.Package) pkgbits.Index {
421 if idx, ok := pw.pkgsIdx[pkg]; ok {
425 w := pw.newWriter(pkgbits.RelocPkg, pkgbits.SyncPkgDef)
426 pw.pkgsIdx[pkg] = w.Idx
428 // The universe and package unsafe need to be handled specially by
429 // importers anyway, so we serialize them using just their package
430 // path. This ensures that readers don't confuse them for
431 // user-defined packages.
433 case nil: // universe
434 w.String("builtin") // same package path used by godoc
438 // TODO(mdempsky): Write out pkg.Path() for curpkg too.
440 if pkg != w.p.curpkg {
443 base.Assertf(path != "builtin" && path != "unsafe", "unexpected path for user-defined package: %q", path)
447 w.Len(len(pkg.Imports()))
448 for _, imp := range pkg.Imports() {
459 anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
460 comparableTypeName = types2.Universe.Lookup("comparable").(*types2.TypeName)
461 runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName)
464 // typ writes a use of the given type into the bitstream.
465 func (w *writer) typ(typ types2.Type) {
466 w.typInfo(w.p.typIdx(typ, w.dict))
469 // typInfo writes a use of the given type (specified as a typeInfo
470 // instead) into the bitstream.
471 func (w *writer) typInfo(info typeInfo) {
472 w.Sync(pkgbits.SyncType)
473 if w.Bool(info.derived) {
477 w.Reloc(pkgbits.RelocType, info.idx)
481 // typIdx returns the index where the export data description of type
482 // can be read back in. If no such index exists yet, it's created.
484 // typIdx also reports whether typ is a derived type; that is, whether
485 // its identity depends on type parameters.
486 func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
487 if idx, ok := pw.typsIdx[typ]; ok {
488 return typeInfo{idx: idx, derived: false}
491 if idx, ok := dict.derivedIdx[typ]; ok {
492 return typeInfo{idx: idx, derived: true}
496 w := pw.newWriter(pkgbits.RelocType, pkgbits.SyncTypeIdx)
499 switch typ := typ.(type) {
501 base.Fatalf("unexpected type: %v (%T)", typ, typ)
504 switch kind := typ.Kind(); {
505 case kind == types2.Invalid:
506 base.Fatalf("unexpected types2.Invalid")
508 case types2.Typ[kind] == typ:
509 w.Code(pkgbits.TypeBasic)
513 // Handle "byte" and "rune" as references to their TypeNames.
514 obj := types2.Universe.Lookup(typ.Name())
515 assert(obj.Type() == typ)
517 w.Code(pkgbits.TypeNamed)
522 obj, targs := splitNamed(typ)
524 // Defined types that are declared within a generic function (and
525 // thus have implicit type parameters) are always derived types.
526 if w.p.hasImplicitTypeParams(obj) {
530 w.Code(pkgbits.TypeNamed)
533 case *types2.TypeParam:
535 w.Code(pkgbits.TypeTypeParam)
536 w.Len(w.dict.typeParamIndex(typ))
539 w.Code(pkgbits.TypeArray)
540 w.Uint64(uint64(typ.Len()))
544 w.Code(pkgbits.TypeChan)
545 w.Len(int(typ.Dir()))
549 w.Code(pkgbits.TypeMap)
553 case *types2.Pointer:
554 w.Code(pkgbits.TypePointer)
557 case *types2.Signature:
558 base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ)
559 w.Code(pkgbits.TypeSignature)
563 w.Code(pkgbits.TypeSlice)
567 w.Code(pkgbits.TypeStruct)
570 case *types2.Interface:
571 // Handle "any" as reference to its TypeName.
572 if typ == anyTypeName.Type() {
573 w.Code(pkgbits.TypeNamed)
574 w.obj(anyTypeName, nil)
578 w.Code(pkgbits.TypeInterface)
582 w.Code(pkgbits.TypeUnion)
587 idx := pkgbits.Index(len(dict.derived))
588 dict.derived = append(dict.derived, derivedInfo{idx: w.Flush()})
589 dict.derivedIdx[typ] = idx
590 return typeInfo{idx: idx, derived: true}
593 pw.typsIdx[typ] = w.Idx
594 return typeInfo{idx: w.Flush(), derived: false}
597 func (w *writer) structType(typ *types2.Struct) {
598 w.Len(typ.NumFields())
599 for i := 0; i < typ.NumFields(); i++ {
609 func (w *writer) unionType(typ *types2.Union) {
611 for i := 0; i < typ.Len(); i++ {
618 func (w *writer) interfaceType(typ *types2.Interface) {
619 // If typ has no embedded types but it's not a basic interface, then
620 // the natural description we write out below will fail to
622 if typ.NumEmbeddeds() == 0 && !typ.IsMethodSet() {
623 // Currently, this can only happen for the underlying Interface of
624 // "comparable", which is needed to handle type declarations like
625 // "type C comparable".
626 assert(typ == comparableTypeName.Type().(*types2.Named).Underlying())
628 // Export as "interface{ comparable }".
629 w.Len(0) // NumExplicitMethods
630 w.Len(1) // NumEmbeddeds
631 w.Bool(false) // IsImplicit
632 w.typ(comparableTypeName.Type()) // EmbeddedType(0)
636 w.Len(typ.NumExplicitMethods())
637 w.Len(typ.NumEmbeddeds())
639 if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 1 {
640 w.Bool(typ.IsImplicit())
642 // Implicit interfaces always have 0 explicit methods and 1
643 // embedded type, so we skip writing out the implicit flag
644 // otherwise as a space optimization.
645 assert(!typ.IsImplicit())
648 for i := 0; i < typ.NumExplicitMethods(); i++ {
649 m := typ.ExplicitMethod(i)
650 sig := m.Type().(*types2.Signature)
651 assert(sig.TypeParams() == nil)
658 for i := 0; i < typ.NumEmbeddeds(); i++ {
659 w.typ(typ.EmbeddedType(i))
663 func (w *writer) signature(sig *types2.Signature) {
664 w.Sync(pkgbits.SyncSignature)
665 w.params(sig.Params())
666 w.params(sig.Results())
667 w.Bool(sig.Variadic())
670 func (w *writer) params(typ *types2.Tuple) {
671 w.Sync(pkgbits.SyncParams)
673 for i := 0; i < typ.Len(); i++ {
678 func (w *writer) param(param *types2.Var) {
679 w.Sync(pkgbits.SyncParam)
687 // obj writes a use of the given object into the bitstream.
689 // If obj is a generic object, then explicits are the explicit type
690 // arguments used to instantiate it (i.e., used to substitute the
691 // object's own declared type parameters).
692 func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) {
693 w.objInfo(w.p.objInstIdx(obj, explicits, w.dict))
696 // objInfo writes a use of the given encoded object into the
698 func (w *writer) objInfo(info objInfo) {
699 w.Sync(pkgbits.SyncObject)
700 w.Bool(false) // TODO(mdempsky): Remove; was derived func inst.
701 w.Reloc(pkgbits.RelocObj, info.idx)
703 w.Len(len(info.explicits))
704 for _, info := range info.explicits {
709 // objInstIdx returns the indices for an object and a corresponding
710 // list of type arguments used to instantiate it, adding them to the
711 // export data as needed.
712 func (pw *pkgWriter) objInstIdx(obj types2.Object, explicits *types2.TypeList, dict *writerDict) objInfo {
713 explicitInfos := make([]typeInfo, explicits.Len())
714 for i := range explicitInfos {
715 explicitInfos[i] = pw.typIdx(explicits.At(i), dict)
717 return objInfo{idx: pw.objIdx(obj), explicits: explicitInfos}
720 // objIdx returns the index for the given Object, adding it to the
721 // export data as needed.
722 func (pw *pkgWriter) objIdx(obj types2.Object) pkgbits.Index {
723 // TODO(mdempsky): Validate that obj is a global object (or a local
724 // defined type, which we hoist to global scope anyway).
726 if idx, ok := pw.objsIdx[obj]; ok {
731 derivedIdx: make(map[types2.Type]pkgbits.Index),
734 if isDefinedType(obj) && obj.Pkg() == pw.curpkg {
735 decl, ok := pw.typDecls[obj.(*types2.TypeName)]
737 dict.implicits = decl.implicits
740 // We encode objects into 4 elements across different sections, all
741 // sharing the same index:
743 // - RelocName has just the object's qualified name (i.e.,
744 // Object.Pkg and Object.Name) and the CodeObj indicating what
745 // specific type of Object it is (Var, Func, etc).
747 // - RelocObj has the remaining public details about the object,
748 // relevant to go/types importers.
750 // - RelocObjExt has additional private details about the object,
751 // which are only relevant to cmd/compile itself. This is
752 // separated from RelocObj so that go/types importers are
753 // unaffected by internal compiler changes.
755 // - RelocObjDict has public details about the object's type
756 // parameters and derived type's used by the object. This is
757 // separated to facilitate the eventual introduction of
758 // shape-based stenciling.
760 // TODO(mdempsky): Re-evaluate whether RelocName still makes sense
761 // to keep separate from RelocObj.
763 w := pw.newWriter(pkgbits.RelocObj, pkgbits.SyncObject1)
764 wext := pw.newWriter(pkgbits.RelocObjExt, pkgbits.SyncObject1)
765 wname := pw.newWriter(pkgbits.RelocName, pkgbits.SyncObject1)
766 wdict := pw.newWriter(pkgbits.RelocObjDict, pkgbits.SyncObject1)
768 pw.objsIdx[obj] = w.Idx // break cycles
769 assert(wext.Idx == w.Idx)
770 assert(wname.Idx == w.Idx)
771 assert(wdict.Idx == w.Idx)
776 code := w.doObj(wext, obj)
780 wname.qualifiedIdent(obj)
784 wdict.objDict(obj, w.dict)
790 // doObj writes the RelocObj definition for obj to w, and the
791 // RelocObjExt definition to wext.
792 func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
793 if obj.Pkg() != w.p.curpkg {
794 return pkgbits.ObjStub
797 switch obj := obj.(type) {
799 w.p.unexpected("object", obj)
806 return pkgbits.ObjConst
809 decl, ok := w.p.funDecls[obj]
811 sig := obj.Type().(*types2.Signature)
814 w.typeParamNames(sig.TypeParams())
818 return pkgbits.ObjFunc
820 case *types2.TypeName:
824 return pkgbits.ObjAlias
827 named := obj.Type().(*types2.Named)
828 assert(named.TypeArgs() == nil)
831 w.typeParamNames(named.TypeParams())
833 w.typ(named.Underlying())
835 w.Len(named.NumMethods())
836 for i := 0; i < named.NumMethods(); i++ {
837 w.method(wext, named.Method(i))
840 return pkgbits.ObjType
846 return pkgbits.ObjVar
850 // objDict writes the dictionary needed for reading the given object.
851 func (w *writer) objDict(obj types2.Object, dict *writerDict) {
852 // TODO(mdempsky): Split objDict into multiple entries? reader.go
853 // doesn't care about the type parameter bounds, and reader2.go
854 // doesn't care about referenced functions.
856 w.dict = dict // TODO(mdempsky): This is a bit sketchy.
858 w.Len(len(dict.implicits))
860 tparams := objTypeParams(obj)
861 ntparams := tparams.Len()
863 for i := 0; i < ntparams; i++ {
864 w.typ(tparams.At(i).Constraint())
867 nderived := len(dict.derived)
869 for _, typ := range dict.derived {
870 w.Reloc(pkgbits.RelocType, typ.idx)
874 // Write runtime dictionary information.
876 // N.B., the go/types importer reads up to the section, but doesn't
877 // read any further, so it's safe to change. (See TODO above.)
879 // For each type parameter, write out whether the constraint is a
880 // basic interface. This is used to determine how aggressively we
881 // can shape corresponding type arguments.
883 // This is somewhat redundant with writing out the full type
884 // parameter constraints above, but the compiler currently skips
885 // over those. Also, we don't care about the *declared* constraints,
886 // but how the type parameters are actually *used*. E.g., if a type
887 // parameter is constrained to `int | uint` but then never used in
888 // arithmetic/conversions/etc, we could shape those together.
889 for _, implicit := range dict.implicits {
890 tparam := implicit.Type().(*types2.TypeParam)
891 w.Bool(tparam.Underlying().(*types2.Interface).IsMethodSet())
893 for i := 0; i < ntparams; i++ {
894 tparam := tparams.At(i)
895 w.Bool(tparam.Underlying().(*types2.Interface).IsMethodSet())
898 w.Len(len(dict.typeParamMethodExprs))
899 for _, info := range dict.typeParamMethodExprs {
900 w.Len(info.typeParamIdx)
901 w.selectorInfo(info.methodInfo)
904 w.Len(len(dict.subdicts))
905 for _, info := range dict.subdicts {
909 w.Len(len(dict.rtypes))
910 for _, info := range dict.rtypes {
914 w.Len(len(dict.itabs))
915 for _, info := range dict.itabs {
917 w.typInfo(info.iface)
920 assert(len(dict.derived) == nderived)
923 func (w *writer) typeParamNames(tparams *types2.TypeParamList) {
924 w.Sync(pkgbits.SyncTypeParamNames)
926 ntparams := tparams.Len()
927 for i := 0; i < ntparams; i++ {
928 tparam := tparams.At(i).Obj()
934 func (w *writer) method(wext *writer, meth *types2.Func) {
935 decl, ok := w.p.funDecls[meth]
937 sig := meth.Type().(*types2.Signature)
939 w.Sync(pkgbits.SyncMethod)
942 w.typeParamNames(sig.RecvTypeParams())
946 w.pos(decl) // XXX: Hack to workaround linker limitations.
950 // qualifiedIdent writes out the name of an object declared at package
951 // scope. (For now, it's also used to refer to local defined types.)
952 func (w *writer) qualifiedIdent(obj types2.Object) {
953 w.Sync(pkgbits.SyncSym)
956 if isDefinedType(obj) && obj.Pkg() == w.p.curpkg {
957 decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
960 // For local defined types, we embed a scope-disambiguation
961 // number directly into their name. types.SplitVargenSuffix then
962 // knows to look for this.
964 // TODO(mdempsky): Find a better solution; this is terrible.
965 name = fmt.Sprintf("%s·%v", name, decl.gen)
973 // TODO(mdempsky): We should be able to omit pkg from both localIdent
974 // and selector, because they should always be known from context.
975 // However, past frustrations with this optimization in iexport make
976 // me a little nervous to try it again.
978 // localIdent writes the name of a locally declared object (i.e.,
979 // objects that can only be accessed by non-qualified name, within the
980 // context of a particular function).
981 func (w *writer) localIdent(obj types2.Object) {
982 assert(!isGlobal(obj))
983 w.Sync(pkgbits.SyncLocalIdent)
988 // selector writes the name of a field or method (i.e., objects that
989 // can only be accessed using selector expressions).
990 func (w *writer) selector(obj types2.Object) {
991 w.selectorInfo(w.p.selectorIdx(obj))
994 func (w *writer) selectorInfo(info selectorInfo) {
995 w.Sync(pkgbits.SyncSelector)
996 w.pkgRef(info.pkgIdx)
997 w.StringRef(info.nameIdx)
1000 func (pw *pkgWriter) selectorIdx(obj types2.Object) selectorInfo {
1001 pkgIdx := pw.pkgIdx(obj.Pkg())
1002 nameIdx := pw.StringIdx(obj.Name())
1003 return selectorInfo{pkgIdx: pkgIdx, nameIdx: nameIdx}
1006 // @@@ Compiler extensions
1008 func (w *writer) funcExt(obj *types2.Func) {
1009 decl, ok := w.p.funDecls[obj]
1012 // TODO(mdempsky): Extend these pragma validation flags to account
1013 // for generics. E.g., linkname probably doesn't make sense at
1016 pragma := asPragmaFlag(decl.Pragma)
1017 if pragma&ir.Systemstack != 0 && pragma&ir.Nosplit != 0 {
1018 w.p.errorf(decl, "go:nosplit and go:systemstack cannot be combined")
1020 wi := asWasmImport(decl.Pragma)
1022 if decl.Body != nil {
1023 if pragma&ir.Noescape != 0 {
1024 w.p.errorf(decl, "can only use //go:noescape with external func implementations")
1027 w.p.errorf(decl, "can only use //go:wasmimport with external func implementations")
1029 if (pragma&ir.UintptrKeepAlive != 0 && pragma&ir.UintptrEscapes == 0) && pragma&ir.Nosplit == 0 {
1030 // Stack growth can't handle uintptr arguments that may
1031 // be pointers (as we don't know which are pointers
1032 // when creating the stack map). Thus uintptrkeepalive
1033 // functions (and all transitive callees) must be
1036 // N.B. uintptrescapes implies uintptrkeepalive but it
1037 // is OK since the arguments must escape to the heap.
1039 // TODO(prattmic): Add recursive nosplit check of callees.
1040 // TODO(prattmic): Functions with no body (i.e.,
1041 // assembly) must also be nosplit, but we can't check
1043 w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit")
1046 if base.Flag.Complete || decl.Name.Value == "init" {
1047 // Linknamed functions are allowed to have no body. Hopefully
1048 // the linkname target has a body. See issue 23311.
1049 // Wasmimport functions are also allowed to have no body.
1050 if _, ok := w.p.linknames[obj]; !ok && wi == nil {
1051 w.p.errorf(decl, "missing function body")
1056 sig, block := obj.Type().(*types2.Signature), decl.Body
1057 body, closureVars := w.p.bodyIdx(sig, block, w.dict)
1058 assert(len(closureVars) == 0)
1060 w.Sync(pkgbits.SyncFuncExt)
1061 w.pragmaFlag(pragma)
1064 if buildcfg.GOARCH == "wasm" {
1074 w.Bool(false) // stub extension
1075 w.Reloc(pkgbits.RelocBody, body)
1076 w.Sync(pkgbits.SyncEOF)
1079 func (w *writer) typeExt(obj *types2.TypeName) {
1080 decl, ok := w.p.typDecls[obj]
1083 w.Sync(pkgbits.SyncTypeExt)
1085 w.pragmaFlag(asPragmaFlag(decl.Pragma))
1087 // No LSym.SymIdx info yet.
1092 func (w *writer) varExt(obj *types2.Var) {
1093 w.Sync(pkgbits.SyncVarExt)
1097 func (w *writer) linkname(obj types2.Object) {
1098 w.Sync(pkgbits.SyncLinkname)
1100 w.String(w.p.linknames[obj])
1103 func (w *writer) pragmaFlag(p ir.PragmaFlag) {
1104 w.Sync(pkgbits.SyncPragma)
1108 // @@@ Function bodies
1110 // bodyIdx returns the index for the given function body (specified by
1111 // block), adding it to the export data
1112 func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx pkgbits.Index, closureVars []posVar) {
1113 w := pw.newWriter(pkgbits.RelocBody, pkgbits.SyncFuncBody)
1118 if w.Bool(block != nil) {
1123 return w.Flush(), w.closureVars
1126 func (w *writer) funcargs(sig *types2.Signature) {
1127 do := func(params *types2.Tuple, result bool) {
1128 for i := 0; i < params.Len(); i++ {
1129 w.funcarg(params.At(i), result)
1133 if recv := sig.Recv(); recv != nil {
1134 w.funcarg(recv, false)
1136 do(sig.Params(), false)
1137 do(sig.Results(), true)
1140 func (w *writer) funcarg(param *types2.Var, result bool) {
1141 if param.Name() != "" || result {
1146 // addLocal records the declaration of a new local variable.
1147 func (w *writer) addLocal(obj *types2.Var) {
1148 idx := len(w.localsIdx)
1150 w.Sync(pkgbits.SyncAddLocal)
1151 if w.p.SyncMarkers() {
1156 if w.localsIdx == nil {
1157 w.localsIdx = make(map[*types2.Var]int)
1159 w.localsIdx[obj] = idx
1162 // useLocal writes a reference to the given local or free variable
1163 // into the bitstream.
1164 func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) {
1165 w.Sync(pkgbits.SyncUseObjLocal)
1167 if idx, ok := w.localsIdx[obj]; w.Bool(ok) {
1172 idx, ok := w.closureVarsIdx[obj]
1174 if w.closureVarsIdx == nil {
1175 w.closureVarsIdx = make(map[*types2.Var]int)
1177 idx = len(w.closureVars)
1178 w.closureVars = append(w.closureVars, posVar{pos, obj})
1179 w.closureVarsIdx[obj] = idx
1184 func (w *writer) openScope(pos syntax.Pos) {
1185 w.Sync(pkgbits.SyncOpenScope)
1189 func (w *writer) closeScope(pos syntax.Pos) {
1190 w.Sync(pkgbits.SyncCloseScope)
1192 w.closeAnotherScope()
1195 func (w *writer) closeAnotherScope() {
1196 w.Sync(pkgbits.SyncCloseAnotherScope)
1201 // stmt writes the given statement into the function body bitstream.
1202 func (w *writer) stmt(stmt syntax.Stmt) {
1203 var stmts []syntax.Stmt
1205 stmts = []syntax.Stmt{stmt}
1210 func (w *writer) stmts(stmts []syntax.Stmt) {
1212 w.Sync(pkgbits.SyncStmts)
1213 for _, stmt := range stmts {
1215 // Any statements after a terminating statement are safe to
1216 // omit, at least until the next labeled statement.
1217 if _, ok := stmt.(*syntax.LabeledStmt); !ok {
1222 dead = w.p.terminates(stmt)
1225 w.Sync(pkgbits.SyncStmtsEnd)
1228 func (w *writer) stmt1(stmt syntax.Stmt) {
1229 switch stmt := stmt.(type) {
1231 w.p.unexpected("statement", stmt)
1233 case nil, *syntax.EmptyStmt:
1236 case *syntax.AssignStmt:
1238 case stmt.Rhs == nil:
1240 w.op(binOps[stmt.Op])
1244 case stmt.Op != 0 && stmt.Op != syntax.Def:
1245 w.Code(stmtAssignOp)
1246 w.op(binOps[stmt.Op])
1251 if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr {
1252 typ = w.p.typeOf(stmt.Lhs)
1254 w.implicitConvExpr(typ, stmt.Rhs)
1257 w.assignStmt(stmt, stmt.Lhs, stmt.Rhs)
1260 case *syntax.BlockStmt:
1264 case *syntax.BranchStmt:
1267 w.op(branchOps[stmt.Tok])
1268 w.optLabel(stmt.Label)
1270 case *syntax.CallStmt:
1273 w.op(callOps[stmt.Tok])
1276 case *syntax.DeclStmt:
1277 for _, decl := range stmt.DeclList {
1281 case *syntax.ExprStmt:
1285 case *syntax.ForStmt:
1289 case *syntax.IfStmt:
1293 case *syntax.LabeledStmt:
1299 case *syntax.ReturnStmt:
1303 resultTypes := w.sig.Results()
1304 dstType := func(i int) types2.Type {
1305 return resultTypes.At(i).Type()
1307 w.multiExpr(stmt, dstType, syntax.UnpackListExpr(stmt.Results))
1309 case *syntax.SelectStmt:
1313 case *syntax.SendStmt:
1314 chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan)
1319 w.implicitConvExpr(chanType.Elem(), stmt.Value)
1321 case *syntax.SwitchStmt:
1327 func (w *writer) assignList(expr syntax.Expr) {
1328 exprs := syntax.UnpackListExpr(expr)
1331 for _, expr := range exprs {
1336 func (w *writer) assign(expr syntax.Expr) {
1337 expr = syntax.Unparen(expr)
1339 if name, ok := expr.(*syntax.Name); ok {
1340 if name.Value == "_" {
1345 if obj, ok := w.p.info.Defs[name]; ok {
1346 obj := obj.(*types2.Var)
1353 // TODO(mdempsky): Minimize locals index size by deferring
1354 // this until the variables actually come into scope.
1364 func (w *writer) declStmt(decl syntax.Decl) {
1365 switch decl := decl.(type) {
1367 w.p.unexpected("declaration", decl)
1369 case *syntax.ConstDecl, *syntax.TypeDecl:
1371 case *syntax.VarDecl:
1372 w.assignStmt(decl, namesAsExpr(decl.NameList), decl.Values)
1376 // assignStmt writes out an assignment for "lhs = rhs".
1377 func (w *writer) assignStmt(pos poser, lhs0, rhs0 syntax.Expr) {
1378 lhs := syntax.UnpackListExpr(lhs0)
1379 rhs := syntax.UnpackListExpr(rhs0)
1384 // As if w.assignList(lhs0).
1386 for _, expr := range lhs {
1390 dstType := func(i int) types2.Type {
1393 // Finding dstType is somewhat involved, because for VarDecl
1394 // statements, the Names are only added to the info.{Defs,Uses}
1395 // maps, not to info.Types.
1396 if name, ok := syntax.Unparen(dst).(*syntax.Name); ok {
1397 if name.Value == "_" {
1398 return nil // ok: no implicit conversion
1399 } else if def, ok := w.p.info.Defs[name].(*types2.Var); ok {
1401 } else if use, ok := w.p.info.Uses[name].(*types2.Var); ok {
1404 w.p.fatalf(dst, "cannot find type of destination object: %v", dst)
1408 return w.p.typeOf(dst)
1411 w.multiExpr(pos, dstType, rhs)
1414 func (w *writer) blockStmt(stmt *syntax.BlockStmt) {
1415 w.Sync(pkgbits.SyncBlockStmt)
1416 w.openScope(stmt.Pos())
1418 w.closeScope(stmt.Rbrace)
1421 func (w *writer) forStmt(stmt *syntax.ForStmt) {
1422 w.Sync(pkgbits.SyncForStmt)
1423 w.openScope(stmt.Pos())
1425 if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) {
1427 w.assignList(rang.Lhs)
1430 xtyp := w.p.typeOf(rang.X)
1431 if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap {
1435 lhs := syntax.UnpackListExpr(rang.Lhs)
1436 assign := func(i int, src types2.Type) {
1440 dst := syntax.Unparen(lhs[i])
1441 if name, ok := dst.(*syntax.Name); ok && name.Value == "_" {
1445 var dstType types2.Type
1447 // For `:=` assignments, the LHS names only appear in Defs,
1448 // not Types (as used by typeOf).
1449 dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type()
1451 dstType = w.p.typeOf(dst)
1454 w.convRTTI(src, dstType)
1457 keyType, valueType := w.p.rangeTypes(rang.X)
1459 assign(1, valueType)
1463 if stmt.Cond != nil && w.p.staticBool(&stmt.Cond) < 0 { // always false
1465 stmt.Body.List = nil
1470 w.optExpr(stmt.Cond)
1474 w.blockStmt(stmt.Body)
1475 w.Bool(w.distinctVars(stmt))
1476 w.closeAnotherScope()
1479 func (w *writer) distinctVars(stmt *syntax.ForStmt) bool {
1480 lv := base.Debug.LoopVar
1481 v := w.p.info.FileVersions[stmt.Pos().Base()]
1482 is122 := v.Major == 0 && v.Minor == 0 || v.Major == 1 && v.Minor >= 22
1484 // Turning off loopvar for 1.22 is only possible with loopvarhash=qn
1486 // Debug.LoopVar values to be preserved for 1.21 compatibility are 1 and 2,
1487 // which are also set (=1) by GOEXPERIMENT=loopvar. The knobs for turning on
1488 // the new, unshared, loopvar behavior apply to versions less than 1.21 because
1489 // (1) 1.21 also did that and (2) this is believed to be the likely use case;
1490 // anyone checking to see if it affects their code will just run the GOEXPERIMENT
1491 // but will not also update all their go.mod files to 1.21.
1493 // -gcflags=-d=loopvar=3 enables logging for 1.22 but does not turn loopvar on for <= 1.21.
1495 return is122 || lv > 0 && lv != 3
1498 // rangeTypes returns the types of values produced by ranging over
1500 func (pw *pkgWriter) rangeTypes(expr syntax.Expr) (key, value types2.Type) {
1501 typ := pw.typeOf(expr)
1502 switch typ := types2.CoreType(typ).(type) {
1503 case *types2.Pointer: // must be pointer to array
1504 return types2.Typ[types2.Int], types2.CoreType(typ.Elem()).(*types2.Array).Elem()
1506 return types2.Typ[types2.Int], typ.Elem()
1508 return types2.Typ[types2.Int], typ.Elem()
1510 if typ.Info()&types2.IsString != 0 {
1511 return types2.Typ[types2.Int], runeTypeName.Type()
1514 return typ.Key(), typ.Elem()
1516 return typ.Elem(), nil
1518 pw.fatalf(expr, "unexpected range type: %v", typ)
1519 panic("unreachable")
1522 func (w *writer) ifStmt(stmt *syntax.IfStmt) {
1523 cond := w.p.staticBool(&stmt.Cond)
1525 w.Sync(pkgbits.SyncIfStmt)
1526 w.openScope(stmt.Pos())
1532 w.blockStmt(stmt.Then)
1534 w.pos(stmt.Then.Rbrace)
1539 w.closeAnotherScope()
1542 func (w *writer) selectStmt(stmt *syntax.SelectStmt) {
1543 w.Sync(pkgbits.SyncSelectStmt)
1546 w.Len(len(stmt.Body))
1547 for i, clause := range stmt.Body {
1549 w.closeScope(clause.Pos())
1551 w.openScope(clause.Pos())
1555 w.stmts(clause.Body)
1557 if len(stmt.Body) > 0 {
1558 w.closeScope(stmt.Rbrace)
1562 func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {
1563 w.Sync(pkgbits.SyncSwitchStmt)
1565 w.openScope(stmt.Pos())
1569 var iface, tagType types2.Type
1570 if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) {
1571 iface = w.p.typeOf(guard.X)
1574 if tag := guard.Lhs; w.Bool(tag != nil) {
1577 // Like w.localIdent, but we don't have a types2.Object.
1578 w.Sync(pkgbits.SyncLocalIdent)
1586 var tagValue constant.Value
1588 tv := w.p.typeAndValue(tag)
1592 tagType = types2.Typ[types2.Bool]
1593 tagValue = constant.MakeBool(true)
1596 if tagValue != nil {
1597 // If the switch tag has a constant value, look for a case
1598 // clause that we always branch to.
1600 var target *syntax.CaseClause
1602 for _, clause := range stmt.Body {
1603 if clause.Cases == nil {
1606 for _, cas := range syntax.UnpackListExpr(clause.Cases) {
1607 tv := w.p.typeAndValue(cas)
1608 if tv.Value == nil {
1609 return // non-constant case; give up
1611 if constant.Compare(tagValue, token.EQL, tv.Value) {
1617 // We've found the target clause, if any.
1620 if hasFallthrough(target.Body) {
1621 return // fallthrough is tricky; give up
1624 // Rewrite as single "default" case.
1626 stmt.Body = []*syntax.CaseClause{target}
1631 // Clear switch tag (i.e., replace with implicit "true").
1634 tagType = types2.Typ[types2.Bool]
1638 // Walk is going to emit comparisons between the tag value and
1639 // each case expression, and we want these comparisons to always
1640 // have the same type. If there are any case values that can't be
1641 // converted to the tag value's type, then convert everything to
1644 for _, clause := range stmt.Body {
1645 for _, cas := range syntax.UnpackListExpr(clause.Cases) {
1646 if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
1647 tagType = types2.NewInterfaceType(nil, nil)
1653 if w.Bool(tag != nil) {
1654 w.implicitConvExpr(tagType, tag)
1658 w.Len(len(stmt.Body))
1659 for i, clause := range stmt.Body {
1661 w.closeScope(clause.Pos())
1663 w.openScope(clause.Pos())
1667 cases := syntax.UnpackListExpr(clause.Cases)
1670 for _, cas := range cases {
1671 if w.Bool(isNil(w.p, cas)) {
1674 w.exprType(iface, cas)
1677 // As if w.exprList(clause.Cases),
1678 // but with implicit conversions to tagType.
1680 w.Sync(pkgbits.SyncExprList)
1681 w.Sync(pkgbits.SyncExprs)
1683 for _, cas := range cases {
1684 w.implicitConvExpr(tagType, cas)
1688 if obj, ok := w.p.info.Implicits[clause]; ok {
1689 // TODO(mdempsky): These pos details are quirkish, but also
1690 // necessary so the variable's position is correct for DWARF
1691 // scope assignment later. It would probably be better for us to
1692 // instead just set the variable's DWARF scoping info earlier so
1693 // we can give it the correct position information.
1695 if typs := syntax.UnpackListExpr(clause.Cases); len(typs) != 0 {
1696 pos = typeExprEndPos(typs[len(typs)-1])
1700 obj := obj.(*types2.Var)
1705 w.stmts(clause.Body)
1707 if len(stmt.Body) > 0 {
1708 w.closeScope(stmt.Rbrace)
1711 w.closeScope(stmt.Rbrace)
1714 func (w *writer) label(label *syntax.Name) {
1715 w.Sync(pkgbits.SyncLabel)
1717 // TODO(mdempsky): Replace label strings with dense indices.
1718 w.String(label.Value)
1721 func (w *writer) optLabel(label *syntax.Name) {
1722 w.Sync(pkgbits.SyncOptLabel)
1723 if w.Bool(label != nil) {
1730 // expr writes the given expression into the function body bitstream.
1731 func (w *writer) expr(expr syntax.Expr) {
1732 base.Assertf(expr != nil, "missing expression")
1734 expr = syntax.Unparen(expr) // skip parens; unneeded after typecheck
1736 obj, inst := lookupObj(w.p, expr)
1737 targs := inst.TypeArgs
1739 if tv, ok := w.p.maybeTypeAndValue(expr); ok {
1741 w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr))
1744 if tv.Value != nil {
1747 typ := idealType(tv)
1752 // TODO(mdempsky): These details are only important for backend
1753 // diagnostics. Explore writing them out separately.
1754 w.op(constExprOp(expr))
1755 w.String(syntax.String(expr))
1759 if _, isNil := obj.(*types2.Nil); isNil {
1766 // With shape types (and particular pointer shaping), we may have
1767 // an expression of type "go.shape.*uint8", but need to reshape it
1768 // to another shape-identical type to allow use in field
1769 // selection, indexing, etc.
1770 if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) {
1778 if targs.Len() != 0 {
1779 obj := obj.(*types2.Func)
1781 w.Code(exprFuncInst)
1783 w.funcInst(obj, targs)
1793 obj := obj.(*types2.Var)
1794 assert(!obj.IsField())
1797 w.useLocal(expr.Pos(), obj)
1801 switch expr := expr.(type) {
1803 w.p.unexpected("expression", expr)
1805 case *syntax.CompositeLit:
1809 case *syntax.FuncLit:
1813 case *syntax.SelectorExpr:
1814 sel, ok := w.p.info.Selections[expr]
1819 w.p.fatalf(expr, "unexpected selection kind: %v", sel.Kind())
1821 case types2.FieldVal:
1822 w.Code(exprFieldVal)
1825 w.selector(sel.Obj())
1827 case types2.MethodVal:
1828 w.Code(exprMethodVal)
1829 typ := w.recvExpr(expr, sel)
1831 w.methodExpr(expr, typ, sel)
1833 case types2.MethodExpr:
1834 w.Code(exprMethodExpr)
1836 tv := w.p.typeAndValue(expr.X)
1839 index := sel.Index()
1840 implicits := index[:len(index)-1]
1845 w.Len(len(implicits))
1846 for _, ix := range implicits {
1848 typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type()
1851 recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type()
1852 if w.Bool(isPtrTo(typ, recv)) { // need deref
1854 } else if w.Bool(isPtrTo(recv, typ)) { // need addr
1859 w.methodExpr(expr, typ, sel)
1862 case *syntax.IndexExpr:
1863 _ = w.p.typeOf(expr.Index) // ensure this is an index expression, not an instantiation
1865 xtyp := w.p.typeOf(expr.X)
1867 var keyType types2.Type
1868 if mapType, ok := types2.CoreType(xtyp).(*types2.Map); ok {
1869 keyType = mapType.Key()
1875 w.implicitConvExpr(keyType, expr.Index)
1880 case *syntax.SliceExpr:
1884 for _, n := range &expr.Index {
1888 case *syntax.AssertExpr:
1889 iface := w.p.typeOf(expr.X)
1894 w.exprType(iface, expr.Type)
1897 case *syntax.Operation:
1900 w.op(unOps[expr.Op])
1906 var commonType types2.Type
1908 case syntax.Shl, syntax.Shr:
1909 // ok: operands are allowed to have different types
1911 xtyp := w.p.typeOf(expr.X)
1912 ytyp := w.p.typeOf(expr.Y)
1914 case types2.AssignableTo(xtyp, ytyp):
1916 case types2.AssignableTo(ytyp, xtyp):
1919 w.p.fatalf(expr, "failed to find common type between %v and %v", xtyp, ytyp)
1923 w.Code(exprBinaryOp)
1924 w.op(binOps[expr.Op])
1925 w.implicitConvExpr(commonType, expr.X)
1927 w.implicitConvExpr(commonType, expr.Y)
1929 case *syntax.CallExpr:
1930 tv := w.p.typeAndValue(expr.Fun)
1932 assert(len(expr.ArgList) == 1)
1933 assert(!expr.HasDots)
1934 w.convertExpr(tv.Type, expr.ArgList[0], false)
1938 var rtype types2.Type
1940 switch obj, _ := lookupObj(w.p, expr.Fun); obj.Name() {
1942 assert(len(expr.ArgList) >= 1)
1943 assert(!expr.HasDots)
1947 w.exprType(nil, expr.ArgList[0])
1948 w.exprs(expr.ArgList[1:])
1950 typ := w.p.typeOf(expr)
1951 switch coreType := types2.CoreType(typ).(type) {
1953 w.p.fatalf(expr, "unexpected core type: %v", coreType)
1959 w.rtype(sliceElem(typ))
1965 assert(len(expr.ArgList) == 1)
1966 assert(!expr.HasDots)
1970 w.exprType(nil, expr.ArgList[0])
1974 rtype = sliceElem(w.p.typeOf(expr))
1976 typ := w.p.typeOf(expr.ArgList[0])
1977 if tuple, ok := typ.(*types2.Tuple); ok { // "copy(g())"
1978 typ = tuple.At(0).Type()
1980 rtype = sliceElem(typ)
1982 typ := w.p.typeOf(expr.ArgList[0])
1983 if tuple, ok := typ.(*types2.Tuple); ok { // "delete(g())"
1984 typ = tuple.At(0).Type()
1988 rtype = sliceElem(w.p.typeOf(expr))
1992 writeFunExpr := func() {
1993 fun := syntax.Unparen(expr.Fun)
1995 if selector, ok := fun.(*syntax.SelectorExpr); ok {
1996 if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal {
1997 w.Bool(true) // method call
1998 typ := w.recvExpr(selector, sel)
1999 w.methodExpr(selector, typ, sel)
2004 w.Bool(false) // not a method call (i.e., normal function call)
2006 if obj, inst := lookupObj(w.p, fun); w.Bool(obj != nil && inst.TypeArgs.Len() != 0) {
2007 obj := obj.(*types2.Func)
2010 w.funcInst(obj, inst.TypeArgs)
2017 sigType := types2.CoreType(tv.Type).(*types2.Signature)
2018 paramTypes := sigType.Params()
2024 paramType := func(i int) types2.Type {
2025 if sigType.Variadic() && !expr.HasDots && i >= paramTypes.Len()-1 {
2026 return paramTypes.At(paramTypes.Len() - 1).Type().(*types2.Slice).Elem()
2028 return paramTypes.At(i).Type()
2031 w.multiExpr(expr, paramType, expr.ArgList)
2032 w.Bool(expr.HasDots)
2039 func sliceElem(typ types2.Type) types2.Type {
2040 return types2.CoreType(typ).(*types2.Slice).Elem()
2043 func (w *writer) optExpr(expr syntax.Expr) {
2044 if w.Bool(expr != nil) {
2049 // recvExpr writes out expr.X, but handles any implicit addressing,
2050 // dereferencing, and field selections appropriate for the method
2052 func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) types2.Type {
2053 index := sel.Index()
2054 implicits := index[:len(index)-1]
2059 w.Len(len(implicits))
2061 typ := w.p.typeOf(expr.X)
2062 for _, ix := range implicits {
2063 typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type()
2067 recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type()
2068 if w.Bool(isPtrTo(typ, recv)) { // needs deref
2070 } else if w.Bool(isPtrTo(recv, typ)) { // needs addr
2077 // funcInst writes a reference to an instantiated function.
2078 func (w *writer) funcInst(obj *types2.Func, targs *types2.TypeList) {
2079 info := w.p.objInstIdx(obj, targs, w.dict)
2081 // Type arguments list contains derived types; we can emit a static
2082 // call to the shaped function, but need to dynamically compute the
2083 // runtime dictionary pointer.
2084 if w.Bool(info.anyDerived()) {
2085 w.Len(w.dict.subdictIdx(info))
2089 // Type arguments list is statically known; we can emit a static
2090 // call with a statically reference to the respective runtime
2095 // methodExpr writes out a reference to the method selected by
2096 // expr. sel should be the corresponding types2.Selection, and recv
2097 // the type produced after any implicit addressing, dereferencing, and
2098 // field selection. (Note: recv might differ from sel.Obj()'s receiver
2099 // parameter in the case of interface types, and is needed for
2100 // handling type parameter methods.)
2101 func (w *writer) methodExpr(expr *syntax.SelectorExpr, recv types2.Type, sel *types2.Selection) {
2102 fun := sel.Obj().(*types2.Func)
2103 sig := fun.Type().(*types2.Signature)
2110 // Method on a type parameter. These require an indirect call
2111 // through the current function's runtime dictionary.
2112 if typeParam, ok := recv.(*types2.TypeParam); w.Bool(ok) {
2113 typeParamIdx := w.dict.typeParamIndex(typeParam)
2114 methodInfo := w.p.selectorIdx(fun)
2116 w.Len(w.dict.typeParamMethodExprIdx(typeParamIdx, methodInfo))
2120 if isInterface(recv) != isInterface(sig.Recv().Type()) {
2121 w.p.fatalf(expr, "isInterface inconsistency: %v and %v", recv, sig.Recv().Type())
2124 if !isInterface(recv) {
2125 if named, ok := deref2(recv).(*types2.Named); ok {
2126 obj, targs := splitNamed(named)
2127 info := w.p.objInstIdx(obj, targs, w.dict)
2129 // Method on a derived receiver type. These can be handled by a
2130 // static call to the shaped method, but require dynamically
2131 // looking up the appropriate dictionary argument in the current
2132 // function's runtime dictionary.
2133 if w.p.hasImplicitTypeParams(obj) || info.anyDerived() {
2134 w.Bool(true) // dynamic subdictionary
2135 w.Len(w.dict.subdictIdx(info))
2139 // Method on a fully known receiver type. These can be handled
2140 // by a static call to the shaped method, and with a static
2141 // reference to the receiver type's dictionary.
2142 if targs.Len() != 0 {
2143 w.Bool(false) // no dynamic subdictionary
2144 w.Bool(true) // static dictionary
2151 w.Bool(false) // no dynamic subdictionary
2152 w.Bool(false) // no static dictionary
2155 // multiExpr writes a sequence of expressions, where the i'th value is
2156 // implicitly converted to dstType(i). It also handles when exprs is a
2157 // single, multi-valued expression (e.g., the multi-valued argument in
2158 // an f(g()) call, or the RHS operand in a comma-ok assignment).
2159 func (w *writer) multiExpr(pos poser, dstType func(int) types2.Type, exprs []syntax.Expr) {
2160 w.Sync(pkgbits.SyncMultiExpr)
2162 if len(exprs) == 1 {
2164 if tuple, ok := w.p.typeOf(expr).(*types2.Tuple); ok {
2165 assert(tuple.Len() > 1)
2166 w.Bool(true) // N:1 assignment
2171 for i := 0; i < tuple.Len(); i++ {
2172 src := tuple.At(i).Type()
2173 // TODO(mdempsky): Investigate not writing src here. I think
2174 // the reader should be able to infer it from expr anyway.
2176 if dst := dstType(i); w.Bool(dst != nil && !types2.Identical(src, dst)) {
2177 if src == nil || dst == nil {
2178 w.p.fatalf(pos, "src is %v, dst is %v", src, dst)
2180 if !types2.AssignableTo(src, dst) {
2181 w.p.fatalf(pos, "%v is not assignable to %v", src, dst)
2184 w.convRTTI(src, dst)
2191 w.Bool(false) // N:N assignment
2193 for i, expr := range exprs {
2194 w.implicitConvExpr(dstType(i), expr)
2198 // implicitConvExpr is like expr, but if dst is non-nil and different
2199 // from expr's type, then an implicit conversion operation is inserted
2200 // at expr's position.
2201 func (w *writer) implicitConvExpr(dst types2.Type, expr syntax.Expr) {
2202 w.convertExpr(dst, expr, true)
2205 func (w *writer) convertExpr(dst types2.Type, expr syntax.Expr, implicit bool) {
2206 src := w.p.typeOf(expr)
2208 // Omit implicit no-op conversions.
2209 identical := dst == nil || types2.Identical(src, dst)
2210 if implicit && identical {
2215 if implicit && !types2.AssignableTo(src, dst) {
2216 w.p.fatalf(expr, "%v is not assignable to %v", src, dst)
2223 w.convRTTI(src, dst)
2224 w.Bool(isTypeParam(dst))
2229 func (w *writer) compLit(lit *syntax.CompositeLit) {
2230 typ := w.p.typeOf(lit)
2232 w.Sync(pkgbits.SyncCompLit)
2236 if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
2239 var keyType, elemType types2.Type
2240 var structType *types2.Struct
2241 switch typ0 := typ; typ := types2.CoreType(typ).(type) {
2243 w.p.fatalf(lit, "unexpected composite literal type: %v", typ)
2245 elemType = typ.Elem()
2248 keyType, elemType = typ.Key(), typ.Elem()
2250 elemType = typ.Elem()
2251 case *types2.Struct:
2255 w.Len(len(lit.ElemList))
2256 for i, elem := range lit.ElemList {
2257 elemType := elemType
2258 if structType != nil {
2259 if kv, ok := elem.(*syntax.KeyValueExpr); ok {
2260 // use position of expr.Key rather than of elem (which has position of ':')
2262 i = fieldIndex(w.p.info, structType, kv.Key.(*syntax.Name))
2267 elemType = structType.Field(i).Type()
2270 if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) {
2271 // use position of expr.Key rather than of elem (which has position of ':')
2273 w.implicitConvExpr(keyType, kv.Key)
2278 w.implicitConvExpr(elemType, elem)
2282 func (w *writer) funcLit(expr *syntax.FuncLit) {
2283 sig := w.p.typeOf(expr).(*types2.Signature)
2285 body, closureVars := w.p.bodyIdx(sig, expr.Body, w.dict)
2287 w.Sync(pkgbits.SyncFuncLit)
2291 w.Len(len(closureVars))
2292 for _, cv := range closureVars {
2294 w.useLocal(cv.pos, cv.var_)
2297 w.Reloc(pkgbits.RelocBody, body)
2300 type posVar struct {
2305 func (w *writer) exprList(expr syntax.Expr) {
2306 w.Sync(pkgbits.SyncExprList)
2307 w.exprs(syntax.UnpackListExpr(expr))
2310 func (w *writer) exprs(exprs []syntax.Expr) {
2311 w.Sync(pkgbits.SyncExprs)
2313 for _, expr := range exprs {
2318 // rtype writes information so that the reader can construct an
2319 // expression of type *runtime._type representing typ.
2320 func (w *writer) rtype(typ types2.Type) {
2321 typ = types2.Default(typ)
2323 info := w.p.typIdx(typ, w.dict)
2327 func (w *writer) rtypeInfo(info typeInfo) {
2328 w.Sync(pkgbits.SyncRType)
2330 if w.Bool(info.derived) {
2331 w.Len(w.dict.rtypeIdx(info))
2337 // varDictIndex writes out information for populating DictIndex for
2338 // the ir.Name that will represent obj.
2339 func (w *writer) varDictIndex(obj *types2.Var) {
2340 info := w.p.typIdx(obj.Type(), w.dict)
2341 if w.Bool(info.derived) {
2342 w.Len(w.dict.rtypeIdx(info))
2346 func isUntyped(typ types2.Type) bool {
2347 basic, ok := typ.(*types2.Basic)
2348 return ok && basic.Info()&types2.IsUntyped != 0
2351 func isTuple(typ types2.Type) bool {
2352 _, ok := typ.(*types2.Tuple)
2356 func (w *writer) itab(typ, iface types2.Type) {
2357 typ = types2.Default(typ)
2358 iface = types2.Default(iface)
2360 typInfo := w.p.typIdx(typ, w.dict)
2361 ifaceInfo := w.p.typIdx(iface, w.dict)
2363 w.rtypeInfo(typInfo)
2364 w.rtypeInfo(ifaceInfo)
2365 if w.Bool(typInfo.derived || ifaceInfo.derived) {
2366 w.Len(w.dict.itabIdx(typInfo, ifaceInfo))
2370 // convRTTI writes information so that the reader can construct
2371 // expressions for converting from src to dst.
2372 func (w *writer) convRTTI(src, dst types2.Type) {
2373 w.Sync(pkgbits.SyncConvRTTI)
2377 func (w *writer) exprType(iface types2.Type, typ syntax.Expr) {
2378 base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface)
2380 tv := w.p.typeAndValue(typ)
2383 w.Sync(pkgbits.SyncExprType)
2386 if w.Bool(iface != nil && !iface.Underlying().(*types2.Interface).Empty()) {
2387 w.itab(tv.Type, iface)
2391 info := w.p.typIdx(tv.Type, w.dict)
2392 w.Bool(info.derived)
2396 // isInterface reports whether typ is known to be an interface type.
2397 // If typ is a type parameter, then isInterface reports an internal
2398 // compiler error instead.
2399 func isInterface(typ types2.Type) bool {
2400 if _, ok := typ.(*types2.TypeParam); ok {
2401 // typ is a type parameter and may be instantiated as either a
2402 // concrete or interface type, so the writer can't depend on
2404 base.Fatalf("%v is a type parameter", typ)
2407 _, ok := typ.Underlying().(*types2.Interface)
2411 // op writes an Op into the bitstream.
2412 func (w *writer) op(op ir.Op) {
2413 // TODO(mdempsky): Remove in favor of explicit codes? Would make
2414 // export data more stable against internal refactorings, but low
2415 // priority at the moment.
2417 w.Sync(pkgbits.SyncOp)
2421 // @@@ Package initialization
2423 // Caution: This code is still clumsy, because toolstash -cmp is
2424 // particularly sensitive to it.
2426 type typeDeclGen struct {
2430 // Implicit type parameters in scope at this type declaration.
2431 implicits []*types2.TypeName
2434 type fileImports struct {
2435 importedEmbed, importedUnsafe bool
2438 // declCollector is a visitor type that collects compiler-needed
2439 // information about declarations that types2 doesn't track.
2441 // Notably, it maps declared types and functions back to their
2442 // declaration statement, keeps track of implicit type parameters, and
2443 // assigns unique type "generation" numbers to local defined types.
2444 type declCollector struct {
2449 implicits []*types2.TypeName
2452 func (c *declCollector) withTParams(obj types2.Object) *declCollector {
2453 tparams := objTypeParams(obj)
2460 copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)]
2461 for i := 0; i < n; i++ {
2462 copy.implicits = append(copy.implicits, tparams.At(i).Obj())
2467 func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
2470 switch n := n.(type) {
2472 pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false)
2474 case *syntax.ImportDecl:
2475 pw.checkPragmas(n.Pragma, 0, false)
2477 switch pkgNameOf(pw.info, n).Imported().Path() {
2479 c.file.importedEmbed = true
2481 c.file.importedUnsafe = true
2484 case *syntax.ConstDecl:
2485 pw.checkPragmas(n.Pragma, 0, false)
2487 case *syntax.FuncDecl:
2488 pw.checkPragmas(n.Pragma, funcPragmas, false)
2490 obj := pw.info.Defs[n.Name].(*types2.Func)
2491 pw.funDecls[obj] = n
2493 return c.withTParams(obj)
2495 case *syntax.TypeDecl:
2496 obj := pw.info.Defs[n.Name].(*types2.TypeName)
2497 d := typeDeclGen{TypeDecl: n, implicits: c.implicits}
2500 pw.checkPragmas(n.Pragma, 0, false)
2502 pw.checkPragmas(n.Pragma, 0, false)
2504 // Assign a unique ID to function-scoped defined types.
2511 pw.typDecls[obj] = d
2513 // TODO(mdempsky): Omit? Not strictly necessary; only matters for
2514 // type declarations within function literals within parameterized
2515 // type declarations, but types2 the function literals will be
2516 // constant folded away.
2517 return c.withTParams(obj)
2519 case *syntax.VarDecl:
2520 pw.checkPragmas(n.Pragma, 0, true)
2522 if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 {
2523 if err := checkEmbed(n, c.file.importedEmbed, c.withinFunc); err != nil {
2524 pw.errorf(p.Embeds[0].Pos, "%s", err)
2528 case *syntax.BlockStmt:
2531 copy.withinFunc = true
2539 func (pw *pkgWriter) collectDecls(noders []*noder) {
2541 for _, p := range noders {
2542 var file fileImports
2544 syntax.Walk(p.file, &declCollector{
2550 pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...)
2552 for _, l := range p.linknames {
2553 if !file.importedUnsafe {
2554 pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
2558 switch obj := pw.curpkg.Scope().Lookup(l.local).(type) {
2559 case *types2.Func, *types2.Var:
2560 if _, ok := pw.linknames[obj]; !ok {
2561 pw.linknames[obj] = l.remote
2563 pw.errorf(l.pos, "duplicate //go:linkname for %s", l.local)
2567 if types.AllowsGoVersion(1, 18) {
2568 pw.errorf(l.pos, "//go:linkname must refer to declared function or variable")
2575 func (pw *pkgWriter) checkPragmas(p syntax.Pragma, allowed ir.PragmaFlag, embedOK bool) {
2579 pragma := p.(*pragmas)
2581 for _, pos := range pragma.Pos {
2582 if pos.Flag&^allowed != 0 {
2583 pw.errorf(pos.Pos, "misplaced compiler directive")
2588 for _, e := range pragma.Embeds {
2589 pw.errorf(e.Pos, "misplaced go:embed directive")
2594 func (w *writer) pkgInit(noders []*noder) {
2595 w.Len(len(w.p.cgoPragmas))
2596 for _, cgoPragma := range w.p.cgoPragmas {
2597 w.Strings(cgoPragma)
2602 w.Sync(pkgbits.SyncDecls)
2603 for _, p := range noders {
2604 for _, decl := range p.file.DeclList {
2610 w.Sync(pkgbits.SyncEOF)
2613 func (w *writer) pkgInitOrder() {
2614 // TODO(mdempsky): Write as a function body instead?
2615 w.Len(len(w.p.info.InitOrder))
2616 for _, init := range w.p.info.InitOrder {
2617 w.Len(len(init.Lhs))
2618 for _, v := range init.Lhs {
2625 func (w *writer) pkgDecl(decl syntax.Decl) {
2626 switch decl := decl.(type) {
2628 w.p.unexpected("declaration", decl)
2630 case *syntax.ImportDecl:
2632 case *syntax.ConstDecl:
2634 w.pkgObjs(decl.NameList...)
2636 case *syntax.FuncDecl:
2637 if decl.Name.Value == "_" {
2638 break // skip blank functions
2641 obj := w.p.info.Defs[decl.Name].(*types2.Func)
2642 sig := obj.Type().(*types2.Signature)
2644 if sig.RecvTypeParams() != nil || sig.TypeParams() != nil {
2645 break // skip generic functions
2648 if recv := sig.Recv(); recv != nil {
2650 w.typ(recvBase(recv))
2656 w.pkgObjs(decl.Name)
2658 case *syntax.TypeDecl:
2659 if len(decl.TParamList) != 0 {
2660 break // skip generic type decls
2663 if decl.Name.Value == "_" {
2664 break // skip blank type decls
2667 name := w.p.info.Defs[decl.Name].(*types2.TypeName)
2668 // Skip type declarations for interfaces that are only usable as
2669 // type parameter bounds.
2670 if iface, ok := name.Type().Underlying().(*types2.Interface); ok && !iface.IsMethodSet() {
2675 w.pkgObjs(decl.Name)
2677 case *syntax.VarDecl:
2679 w.pkgObjs(decl.NameList...)
2681 var embeds []pragmaEmbed
2682 if p, ok := decl.Pragma.(*pragmas); ok {
2686 for _, embed := range embeds {
2688 w.Strings(embed.Patterns)
2693 func (w *writer) pkgObjs(names ...*syntax.Name) {
2694 w.Sync(pkgbits.SyncDeclNames)
2697 for _, name := range names {
2698 obj, ok := w.p.info.Defs[name]
2701 w.Sync(pkgbits.SyncDeclName)
2708 // staticBool analyzes a boolean expression and reports whether it's
2709 // always true (positive result), always false (negative result), or
2712 // It also simplifies the expression while preserving semantics, if
2714 func (pw *pkgWriter) staticBool(ep *syntax.Expr) int {
2715 if val := pw.typeAndValue(*ep).Value; val != nil {
2716 if constant.BoolVal(val) {
2723 if e, ok := (*ep).(*syntax.Operation); ok {
2726 return pw.staticBool(&e.X)
2729 x := pw.staticBool(&e.X)
2735 y := pw.staticBool(&e.Y)
2737 if pw.typeAndValue(e.X).Value != nil {
2744 x := pw.staticBool(&e.X)
2750 y := pw.staticBool(&e.Y)
2752 if pw.typeAndValue(e.X).Value != nil {
2763 // hasImplicitTypeParams reports whether obj is a defined type with
2764 // implicit type parameters (e.g., declared within a generic function
2766 func (pw *pkgWriter) hasImplicitTypeParams(obj *types2.TypeName) bool {
2767 if obj.Pkg() == pw.curpkg {
2768 decl, ok := pw.typDecls[obj]
2770 if len(decl.implicits) != 0 {
2777 // isDefinedType reports whether obj is a defined type.
2778 func isDefinedType(obj types2.Object) bool {
2779 if obj, ok := obj.(*types2.TypeName); ok {
2780 return !obj.IsAlias()
2785 // isGlobal reports whether obj was declared at package scope.
2787 // Caveat: blank objects are not declared.
2788 func isGlobal(obj types2.Object) bool {
2789 return obj.Parent() == obj.Pkg().Scope()
2792 // lookupObj returns the object that expr refers to, if any. If expr
2793 // is an explicit instantiation of a generic object, then the instance
2794 // object is returned as well.
2795 func lookupObj(p *pkgWriter, expr syntax.Expr) (obj types2.Object, inst types2.Instance) {
2796 if index, ok := expr.(*syntax.IndexExpr); ok {
2797 args := syntax.UnpackListExpr(index.Index)
2799 tv := p.typeAndValue(args[0])
2801 return // normal index expression
2808 // Strip package qualifier, if present.
2809 if sel, ok := expr.(*syntax.SelectorExpr); ok {
2810 if !isPkgQual(p.info, sel) {
2811 return // normal selector expression
2816 if name, ok := expr.(*syntax.Name); ok {
2817 obj = p.info.Uses[name]
2818 inst = p.info.Instances[name]
2823 // isPkgQual reports whether the given selector expression is a
2824 // package-qualified identifier.
2825 func isPkgQual(info *types2.Info, sel *syntax.SelectorExpr) bool {
2826 if name, ok := sel.X.(*syntax.Name); ok {
2827 _, isPkgName := info.Uses[name].(*types2.PkgName)
2833 // isNil reports whether expr is a (possibly parenthesized) reference
2834 // to the predeclared nil value.
2835 func isNil(p *pkgWriter, expr syntax.Expr) bool {
2836 tv := p.typeAndValue(expr)
2840 // isBuiltin reports whether expr is a (possibly parenthesized)
2841 // referenced to the specified built-in function.
2842 func (pw *pkgWriter) isBuiltin(expr syntax.Expr, builtin string) bool {
2843 if name, ok := syntax.Unparen(expr).(*syntax.Name); ok && name.Value == builtin {
2844 return pw.typeAndValue(name).IsBuiltin()
2849 // recvBase returns the base type for the given receiver parameter.
2850 func recvBase(recv *types2.Var) *types2.Named {
2852 if ptr, ok := typ.(*types2.Pointer); ok {
2855 return typ.(*types2.Named)
2858 // namesAsExpr returns a list of names as a syntax.Expr.
2859 func namesAsExpr(names []*syntax.Name) syntax.Expr {
2860 if len(names) == 1 {
2864 exprs := make([]syntax.Expr, len(names))
2865 for i, name := range names {
2868 return &syntax.ListExpr{ElemList: exprs}
2871 // fieldIndex returns the index of the struct field named by key.
2872 func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int {
2873 field := info.Uses[key].(*types2.Var)
2875 for i := 0; i < str.NumFields(); i++ {
2876 if str.Field(i) == field {
2881 panic(fmt.Sprintf("%s: %v is not a field of %v", key.Pos(), field, str))
2884 // objTypeParams returns the type parameters on the given object.
2885 func objTypeParams(obj types2.Object) *types2.TypeParamList {
2886 switch obj := obj.(type) {
2888 sig := obj.Type().(*types2.Signature)
2889 if sig.Recv() != nil {
2890 return sig.RecvTypeParams()
2892 return sig.TypeParams()
2893 case *types2.TypeName:
2895 return obj.Type().(*types2.Named).TypeParams()
2901 // splitNamed decomposes a use of a defined type into its original
2902 // type definition and the type arguments used to instantiate it.
2903 func splitNamed(typ *types2.Named) (*types2.TypeName, *types2.TypeList) {
2904 base.Assertf(typ.TypeParams().Len() == typ.TypeArgs().Len(), "use of uninstantiated type: %v", typ)
2906 orig := typ.Origin()
2907 base.Assertf(orig.TypeArgs() == nil, "origin %v of %v has type arguments", orig, typ)
2908 base.Assertf(typ.Obj() == orig.Obj(), "%v has object %v, but %v has object %v", typ, typ.Obj(), orig, orig.Obj())
2910 return typ.Obj(), typ.TypeArgs()
2913 func asPragmaFlag(p syntax.Pragma) ir.PragmaFlag {
2917 return p.(*pragmas).Flag
2920 func asWasmImport(p syntax.Pragma) *WasmImport {
2924 return p.(*pragmas).WasmImport
2927 // isPtrTo reports whether from is the type *to.
2928 func isPtrTo(from, to types2.Type) bool {
2929 ptr, ok := from.(*types2.Pointer)
2930 return ok && types2.Identical(ptr.Elem(), to)
2933 // hasFallthrough reports whether stmts ends in a fallthrough
2935 func hasFallthrough(stmts []syntax.Stmt) bool {
2936 last, ok := lastNonEmptyStmt(stmts).(*syntax.BranchStmt)
2937 return ok && last.Tok == syntax.Fallthrough
2940 // lastNonEmptyStmt returns the last non-empty statement in list, if
2942 func lastNonEmptyStmt(stmts []syntax.Stmt) syntax.Stmt {
2943 for i := len(stmts) - 1; i >= 0; i-- {
2945 if _, ok := stmt.(*syntax.EmptyStmt); !ok {
2952 // terminates reports whether stmt terminates normal control flow
2953 // (i.e., does not merely advance to the following statement).
2954 func (pw *pkgWriter) terminates(stmt syntax.Stmt) bool {
2955 switch stmt := stmt.(type) {
2956 case *syntax.BranchStmt:
2957 if stmt.Tok == syntax.Goto {
2960 case *syntax.ReturnStmt:
2962 case *syntax.ExprStmt:
2963 if call, ok := syntax.Unparen(stmt.X).(*syntax.CallExpr); ok {
2964 if pw.isBuiltin(call.Fun, "panic") {
2969 // The handling of BlockStmt here is approximate, but it serves to
2970 // allow dead-code elimination for:
2976 case *syntax.IfStmt:
2977 cond := pw.staticBool(&stmt.Cond)
2978 return (cond < 0 || pw.terminates(stmt.Then)) && (cond > 0 || pw.terminates(stmt.Else))
2979 case *syntax.BlockStmt:
2980 return pw.terminates(lastNonEmptyStmt(stmt.List))