src/cmd/compile/internal/noder/writer.go GO 3,401 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,401.
1// Copyright 2021 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package noder67import (8	"fmt"9	"go/constant"10	"go/token"11	"go/version"12	"internal/buildcfg"13	"internal/pkgbits"14	"os"15	"slices"16	"strings"1718	"cmd/compile/internal/base"19	"cmd/compile/internal/ir"20	"cmd/compile/internal/syntax"21	"cmd/compile/internal/types"22	"cmd/compile/internal/types2"23)2425// This file implements the Unified IR package writer and defines the26// Unified IR export data format.27//28// Low-level coding details (e.g., byte-encoding of individual29// primitive values, or handling element bitstreams and30// cross-references) are handled by internal/pkgbits, so here we only31// concern ourselves with higher-level worries like mapping Go32// language constructs into elements.3334// There are two central types in the writing process: the "writer"35// type handles writing out individual elements, while the "pkgWriter"36// type keeps track of which elements have already been created.37//38// For each sort of "thing" (e.g., position, package, object, type)39// that can be written into the export data, there are generally40// several methods that work together:41//42// - writer.thing handles writing out a *use* of a thing, which often43//   means writing a relocation to that thing's encoded index.44//45// - pkgWriter.thingIdx handles reserving an index for a thing, and46//   writing out any elements needed for the thing.47//48// - writer.doThing handles writing out the *definition* of a thing,49//   which in general is a mix of low-level coding primitives (e.g.,50//   ints and strings) or uses of other things.51//52// A design goal of Unified IR is to have a single, canonical writer53// implementation, but multiple reader implementations each tailored54// to their respective needs. For example, within cmd/compile's own55// backend, inlining is implemented largely by just re-running the56// function body reading code.5758// TODO(mdempsky): Add an importer for Unified IR to the x/tools repo,59// and better document the file format boundary between public and60// private data.6162type index = pkgbits.Index6364func assert(p bool) { base.Assert(p) }6566// A pkgWriter constructs Unified IR export data from the results of67// running the types2 type checker on a Go compilation unit.68type pkgWriter struct {69	pkgbits.PkgEncoder7071	m                     posMap72	curpkg                *types2.Package73	info                  *types2.Info74	rangeFuncBodyClosures map[*syntax.FuncLit]bool // non-public information, e.g., which functions are closures range function bodies?7576	// Indices for previously written syntax and types2 things.7778	posBasesIdx map[*syntax.PosBase]index79	pkgsIdx     map[*types2.Package]index80	typsIdx     map[types2.Type]index81	objsIdx     map[types2.Object]index8283	// Maps from types2.Objects back to their syntax.Decl.8485	funDecls map[*types2.Func]*syntax.FuncDecl86	typDecls map[*types2.TypeName]typeDeclGen8788	// linknames maps package-scope objects to their linker symbol name,89	// if specified by a //go:linkname or //go:linknamestd directive.90	linknames map[types2.Object]struct {91		remote string92		std    bool93	}9495	// cgoPragmas accumulates any //go:cgo_* pragmas that need to be96	// passed through to cmd/link.97	cgoPragmas [][]string98}99100// newPkgWriter returns an initialized pkgWriter for the specified101// package.102func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo map[*syntax.FuncLit]bool) *pkgWriter {103	return &pkgWriter{104		PkgEncoder: pkgbits.NewPkgEncoder(uirVersion, base.Debug.SyncFrames),105106		m:                     m,107		curpkg:                pkg,108		info:                  info,109		rangeFuncBodyClosures: otherInfo,110111		pkgsIdx: make(map[*types2.Package]index),112		objsIdx: make(map[types2.Object]index),113		typsIdx: make(map[types2.Type]index),114115		posBasesIdx: make(map[*syntax.PosBase]index),116117		funDecls: make(map[*types2.Func]*syntax.FuncDecl),118		typDecls: make(map[*types2.TypeName]typeDeclGen),119120		linknames: make(map[types2.Object]struct {121			remote string122			std    bool123		}),124	}125}126127// errorf reports a user error about thing p.128func (pw *pkgWriter) errorf(p poser, msg string, args ...any) {129	base.ErrorfAt(pw.m.pos(p), 0, msg, args...)130}131132// fatalf reports an internal compiler error about thing p.133func (pw *pkgWriter) fatalf(p poser, msg string, args ...any) {134	base.FatalfAt(pw.m.pos(p), msg, args...)135}136137// unexpected reports a fatal error about a thing of unexpected138// dynamic type.139func (pw *pkgWriter) unexpected(what string, p poser) {140	pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p)141}142143func (pw *pkgWriter) typeAndValue(x syntax.Expr) syntax.TypeAndValue {144	tv, ok := pw.maybeTypeAndValue(x)145	if !ok {146		pw.fatalf(x, "missing Types entry: %v", syntax.String(x))147	}148	return tv149}150151func (pw *pkgWriter) maybeTypeAndValue(x syntax.Expr) (syntax.TypeAndValue, bool) {152	tv := x.GetTypeInfo()153154	// If x is a generic function whose type arguments are inferred155	// from assignment context, then we need to find its inferred type156	// in Info.Instances instead.157	if name, ok := x.(*syntax.Name); ok {158		if inst, ok := pw.info.Instances[name]; ok {159			tv.Type = inst.Type160		}161	}162163	return tv, tv.Type != nil164}165166// typeOf returns the Type of the given value expression.167func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type {168	tv := pw.typeAndValue(expr)169	if !tv.IsValue() {170		pw.fatalf(expr, "expected value: %v", syntax.String(expr))171	}172	return tv.Type173}174175// A writer provides APIs for writing out an individual element.176type writer struct {177	p *pkgWriter178179	*pkgbits.Encoder180181	// sig holds the signature for the current function body, if any.182	sig *types2.Signature183184	// TODO(mdempsky): We should be able to prune localsIdx whenever a185	// scope closes, and then maybe we can just use the same map for186	// storing the TypeParams too (as their TypeName instead).187188	// localsIdx tracks any local variables declared within this189	// function body. It's unused for writing out non-body things.190	localsIdx map[*types2.Var]int191192	// closureVars tracks any free variables that are referenced by this193	// function body. It's unused for writing out non-body things.194	closureVars    []posVar195	closureVarsIdx map[*types2.Var]int // index of previously seen free variables196197	dict *writerDict198199	// derived tracks whether the type being written out references any200	// type parameters. It's unused for writing non-type things.201	derived bool202}203204// A writerDict tracks types and objects that are used by a declaration.205type writerDict struct {206	// implicits contains type parameters from enclosing declarations.207	implicits []*types2.TypeParam208	// receivers contains receiver type parameters of the declaration.209	receivers []*types2.TypeParam210211	// derived is a slice of type indices for computing derived types212	// (i.e., types that depend on the declaration's type parameters).213	derived []derivedInfo214215	// derivedIdx maps a Type to its corresponding index within the216	// derived slice, if present.217	derivedIdx map[types2.Type]index218219	// These slices correspond to entries in the runtime dictionary.220	typeParamMethodExprs []writerMethodExprInfo221	subdicts             []objInfo222	rtypes               []typeInfo223	itabs                []itabInfo224}225226type itabInfo struct {227	typ   typeInfo228	iface typeInfo229}230231// typeParamIndex returns the index of the given type parameter within232// the dictionary. This may differ from typ.Index() when there are233// implicit or receiver type parameters.234func (dict *writerDict) typeParamIndex(typ *types2.TypeParam) int {235	for idx, implicit := range dict.implicits {236		if implicit == typ {237			return idx238		}239	}240241	for idx, receiver := range dict.receivers {242		if receiver == typ {243			return len(dict.implicits) + idx244		}245	}246247	return len(dict.implicits) + len(dict.receivers) + typ.Index()248}249250// A derivedInfo represents a reference to an encoded generic Go type.251type derivedInfo struct {252	idx index253}254255// A typeInfo represents a reference to an encoded Go type.256//257// If derived is true, then the typeInfo represents a generic Go type258// that contains type parameters. In this case, idx is an index into259// the readerDict.derived{,Types} arrays.260//261// Otherwise, the typeInfo represents a non-generic Go type, and idx262// is an index into the reader.typs array instead.263type typeInfo struct {264	idx     index265	derived bool266}267268// An objInfo represents a reference to an encoded, instantiated (if269// applicable) Go object.270type objInfo struct {271	idx       index      // index for the generic function declaration272	explicits []typeInfo // info for the type arguments273}274275// A selectorInfo represents a reference to an encoded field or method276// name (i.e., objects that can only be accessed using selector277// expressions).278type selectorInfo struct {279	pkgIdx  index280	nameIdx index281}282283// anyDerived reports whether any of info's explicit type arguments284// are derived types.285func (info objInfo) anyDerived() bool {286	for _, explicit := range info.explicits {287		if explicit.derived {288			return true289		}290	}291	return false292}293294// equals reports whether info and other represent the same Go object295// (i.e., same base object and identical type arguments, if any).296func (info objInfo) equals(other objInfo) bool {297	if info.idx != other.idx {298		return false299	}300	assert(len(info.explicits) == len(other.explicits))301	for i, targ := range info.explicits {302		if targ != other.explicits[i] {303			return false304		}305	}306	return true307}308309type writerMethodExprInfo struct {310	typeParamIdx int311	methodInfo   selectorInfo312}313314// typeParamMethodExprIdx returns the index where the given encoded315// method expression function pointer appears within this dictionary's316// type parameters method expressions section, adding it if necessary.317func (dict *writerDict) typeParamMethodExprIdx(typeParamIdx int, methodInfo selectorInfo) int {318	newInfo := writerMethodExprInfo{typeParamIdx, methodInfo}319320	for idx, oldInfo := range dict.typeParamMethodExprs {321		if oldInfo == newInfo {322			return idx323		}324	}325326	idx := len(dict.typeParamMethodExprs)327	dict.typeParamMethodExprs = append(dict.typeParamMethodExprs, newInfo)328	return idx329}330331// subdictIdx returns the index where the given encoded object's332// runtime dictionary appears within this dictionary's subdictionary333// section, adding it if necessary.334func (dict *writerDict) subdictIdx(newInfo objInfo) int {335	for idx, oldInfo := range dict.subdicts {336		if oldInfo.equals(newInfo) {337			return idx338		}339	}340341	idx := len(dict.subdicts)342	dict.subdicts = append(dict.subdicts, newInfo)343	return idx344}345346// rtypeIdx returns the index where the given encoded type's347// *runtime._type value appears within this dictionary's rtypes348// section, adding it if necessary.349func (dict *writerDict) rtypeIdx(newInfo typeInfo) int {350	for idx, oldInfo := range dict.rtypes {351		if oldInfo == newInfo {352			return idx353		}354	}355356	idx := len(dict.rtypes)357	dict.rtypes = append(dict.rtypes, newInfo)358	return idx359}360361// itabIdx returns the index where the given encoded type pair's362// *runtime.itab value appears within this dictionary's itabs section,363// adding it if necessary.364func (dict *writerDict) itabIdx(typInfo, ifaceInfo typeInfo) int {365	newInfo := itabInfo{typInfo, ifaceInfo}366367	for idx, oldInfo := range dict.itabs {368		if oldInfo == newInfo {369			return idx370		}371	}372373	idx := len(dict.itabs)374	dict.itabs = append(dict.itabs, newInfo)375	return idx376}377378func (pw *pkgWriter) newWriter(k pkgbits.SectionKind, marker pkgbits.SyncMarker) *writer {379	return &writer{380		Encoder: pw.NewEncoder(k, marker),381		p:       pw,382	}383}384385// @@@ Positions386387// pos writes the position of p into the element bitstream.388func (w *writer) pos(p poser) {389	w.Sync(pkgbits.SyncPos)390	pos := p.Pos()391392	// TODO(mdempsky): Track down the remaining cases here and fix them.393	if !w.Bool(pos.IsKnown()) {394		return395	}396397	// TODO(mdempsky): Delta encoding.398	w.posBase(pos.Base())399	w.Uint(pos.Line())400	w.Uint(pos.Col())401}402403// posBase writes a reference to the given PosBase into the element404// bitstream.405func (w *writer) posBase(b *syntax.PosBase) {406	w.Reloc(pkgbits.SectionPosBase, w.p.posBaseIdx(b))407}408409// posBaseIdx returns the index for the given PosBase.410func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) index {411	if idx, ok := pw.posBasesIdx[b]; ok {412		return idx413	}414415	w := pw.newWriter(pkgbits.SectionPosBase, pkgbits.SyncPosBase)416	w.p.posBasesIdx[b] = w.Idx417418	w.String(trimFilename(b))419420	if !w.Bool(b.IsFileBase()) {421		w.pos(b)422		w.Uint(b.Line())423		w.Uint(b.Col())424	}425426	return w.Flush()427}428429// @@@ Packages430431// pkg writes a use of the given Package into the element bitstream.432func (w *writer) pkg(pkg *types2.Package) {433	w.pkgRef(w.p.pkgIdx(pkg))434}435436func (w *writer) pkgRef(idx index) {437	w.Sync(pkgbits.SyncPkg)438	w.Reloc(pkgbits.SectionPkg, idx)439}440441// pkgIdx returns the index for the given package, adding it to the442// package export data if needed.443func (pw *pkgWriter) pkgIdx(pkg *types2.Package) index {444	if idx, ok := pw.pkgsIdx[pkg]; ok {445		return idx446	}447448	w := pw.newWriter(pkgbits.SectionPkg, pkgbits.SyncPkgDef)449	pw.pkgsIdx[pkg] = w.Idx450451	// The universe and package unsafe need to be handled specially by452	// importers anyway, so we serialize them using just their package453	// path. This ensures that readers don't confuse them for454	// user-defined packages.455	switch pkg {456	case nil: // universe457		w.String("builtin") // same package path used by godoc458	case types2.Unsafe:459		w.String("unsafe")460	default:461		// TODO(mdempsky): Write out pkg.Path() for curpkg too.462		var path string463		if pkg != w.p.curpkg {464			path = pkg.Path()465		}466		base.Assertf(path != "builtin" && path != "unsafe", "unexpected path for user-defined package: %q", path)467		w.String(path)468		w.String(pkg.Name())469470		w.Len(len(pkg.Imports()))471		for _, imp := range pkg.Imports() {472			w.pkg(imp)473		}474	}475476	return w.Flush()477}478479// @@@ Types480481var (482	anyTypeName        = types2.Universe.Lookup("any").(*types2.TypeName)483	comparableTypeName = types2.Universe.Lookup("comparable").(*types2.TypeName)484	runeTypeName       = types2.Universe.Lookup("rune").(*types2.TypeName)485)486487// typ writes a use of the given type into the bitstream.488func (w *writer) typ(typ types2.Type) {489	w.typInfo(w.p.typIdx(typ, w.dict))490}491492// typInfo writes a use of the given type (specified as a typeInfo493// instead) into the bitstream.494func (w *writer) typInfo(info typeInfo) {495	w.Sync(pkgbits.SyncType)496	if w.Bool(info.derived) {497		w.Len(int(info.idx))498		w.derived = true499	} else {500		w.Reloc(pkgbits.SectionType, info.idx)501	}502}503504// typIdx returns the index where the export data description of type505// can be read back in. If no such index exists yet, it's created.506//507// typIdx also reports whether typ is a derived type; that is, whether508// its identity depends on type parameters.509func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {510	// Strip non-global aliases, because they only appear in inline511	// bodies anyway. Otherwise, they can cause types.Sym collisions512	// (e.g., "main.C" for both of the local type aliases in513	// test/fixedbugs/issue50190.go).514	for {515		if alias, ok := typ.(*types2.Alias); ok && !isGlobal(alias.Obj()) {516			typ = alias.Rhs()517		} else {518			break519		}520	}521522	if idx, ok := pw.typsIdx[typ]; ok {523		return typeInfo{idx: idx, derived: false}524	}525	if dict != nil {526		if idx, ok := dict.derivedIdx[typ]; ok {527			return typeInfo{idx: idx, derived: true}528		}529	}530531	w := pw.newWriter(pkgbits.SectionType, pkgbits.SyncTypeIdx)532	w.dict = dict533534	switch typ := typ.(type) {535	default:536		base.Fatalf("unexpected type: %v (%T)", typ, typ)537538	case *types2.Basic:539		switch kind := typ.Kind(); {540		case kind == types2.Invalid:541			base.Fatalf("unexpected types2.Invalid")542543		case types2.Typ[kind] == typ:544			w.Code(pkgbits.TypeBasic)545			w.Len(int(kind))546547		default:548			// Handle "byte" and "rune" as references to their TypeNames.549			obj := types2.Universe.Lookup(typ.Name()).(*types2.TypeName)550			assert(obj.Type() == typ)551552			w.Code(pkgbits.TypeNamed)553			w.namedType(obj, nil)554		}555556	case *types2.Named:557		w.Code(pkgbits.TypeNamed)558		w.namedType(splitNamed(typ))559560	case *types2.Alias:561		w.Code(pkgbits.TypeNamed)562		w.namedType(splitAlias(typ))563564	case *types2.TypeParam:565		w.derived = true566		w.Code(pkgbits.TypeTypeParam)567		w.Len(w.dict.typeParamIndex(typ))568569	case *types2.Array:570		w.Code(pkgbits.TypeArray)571		w.Uint64(uint64(typ.Len()))572		w.typ(typ.Elem())573574	case *types2.Chan:575		w.Code(pkgbits.TypeChan)576		w.Len(int(typ.Dir()))577		w.typ(typ.Elem())578579	case *types2.Map:580		w.Code(pkgbits.TypeMap)581		w.typ(typ.Key())582		w.typ(typ.Elem())583584	case *types2.Pointer:585		w.Code(pkgbits.TypePointer)586		w.typ(typ.Elem())587588	case *types2.Signature:589		base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ)590		w.Code(pkgbits.TypeSignature)591		w.signature(typ)592593	case *types2.Slice:594		w.Code(pkgbits.TypeSlice)595		w.typ(typ.Elem())596597	case *types2.Struct:598		w.Code(pkgbits.TypeStruct)599		w.structType(typ)600601	case *types2.Interface:602		// Handle "any" as reference to its TypeName.603		// The underlying "any" interface is canonical, so this logic handles both604		// GODEBUG=gotypesalias=1 (when any is represented as a types2.Alias), and605		// gotypesalias=0.606		if types2.Unalias(typ) == types2.Unalias(anyTypeName.Type()) {607			w.Code(pkgbits.TypeNamed)608			w.obj(anyTypeName, nil)609			break610		}611612		w.Code(pkgbits.TypeInterface)613		w.interfaceType(typ)614615	case *types2.Union:616		w.Code(pkgbits.TypeUnion)617		w.unionType(typ)618	}619620	if w.derived {621		idx := index(len(dict.derived))622		dict.derived = append(dict.derived, derivedInfo{idx: w.Flush()})623		dict.derivedIdx[typ] = idx624		return typeInfo{idx: idx, derived: true}625	}626627	pw.typsIdx[typ] = w.Idx628	return typeInfo{idx: w.Flush(), derived: false}629}630631// namedType writes a use of the given named type into the bitstream.632func (w *writer) namedType(obj *types2.TypeName, targs []types2.Type) {633	// Named types that are declared within a generic function (and634	// thus have implicit type parameters) are always derived types.635	if w.p.hasImplicitTypeParams(obj) {636		w.derived = true637	}638639	w.obj(obj, targs)640}641642func (w *writer) structType(typ *types2.Struct) {643	w.Len(typ.NumFields())644	for i := 0; i < typ.NumFields(); i++ {645		f := typ.Field(i)646		w.pos(f)647		w.selector(f)648		w.typ(f.Type())649		w.String(typ.Tag(i))650		w.Bool(f.Embedded())651	}652}653654func (w *writer) unionType(typ *types2.Union) {655	w.Len(typ.Len())656	for i := 0; i < typ.Len(); i++ {657		t := typ.Term(i)658		w.Bool(t.Tilde())659		w.typ(t.Type())660	}661}662663func (w *writer) interfaceType(typ *types2.Interface) {664	// If typ has no embedded types but it's not a basic interface, then665	// the natural description we write out below will fail to666	// reconstruct it.667	if typ.NumEmbeddeds() == 0 && !typ.IsMethodSet() {668		// Currently, this can only happen for the underlying Interface of669		// "comparable", which is needed to handle type declarations like670		// "type C comparable".671		assert(typ == comparableTypeName.Type().(*types2.Named).Underlying())672673		// Export as "interface{ comparable }".674		w.Len(0)                         // NumExplicitMethods675		w.Len(1)                         // NumEmbeddeds676		w.Bool(false)                    // IsImplicit677		w.typ(comparableTypeName.Type()) // EmbeddedType(0)678		return679	}680681	w.Len(typ.NumExplicitMethods())682	w.Len(typ.NumEmbeddeds())683684	if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 1 {685		w.Bool(typ.IsImplicit())686	} else {687		// Implicit interfaces always have 0 explicit methods and 1688		// embedded type, so we skip writing out the implicit flag689		// otherwise as a space optimization.690		assert(!typ.IsImplicit())691	}692693	for i := 0; i < typ.NumExplicitMethods(); i++ {694		m := typ.ExplicitMethod(i)695		sig := m.Type().(*types2.Signature)696		assert(sig.TypeParams() == nil)697698		w.pos(m)699		w.selector(m)700		w.signature(sig)701	}702703	for i := 0; i < typ.NumEmbeddeds(); i++ {704		w.typ(typ.EmbeddedType(i))705	}706}707708func (w *writer) signature(sig *types2.Signature) {709	w.Sync(pkgbits.SyncSignature)710	w.params(sig.Params())711	w.params(sig.Results())712	w.Bool(sig.Variadic())713}714715func (w *writer) params(typ *types2.Tuple) {716	w.Sync(pkgbits.SyncParams)717	w.Len(typ.Len())718	for i := 0; i < typ.Len(); i++ {719		w.param(typ.At(i))720	}721}722723func (w *writer) param(param *types2.Var) {724	w.Sync(pkgbits.SyncParam)725	w.pos(param)726	w.localIdent(param)727	w.typ(param.Type())728}729730// @@@ Objects731732// obj writes a use of the given object into the bitstream.733//734// If obj is a generic object, then explicits are the explicit type735// arguments used to instantiate it (i.e., used to substitute the736// object's own declared type parameters).737func (w *writer) obj(obj types2.Object, explicits []types2.Type) {738	w.objInfo(w.p.objInstIdx(obj, explicits, w.dict))739}740741// objInfo writes a use of the given encoded object into the742// bitstream.743func (w *writer) objInfo(info objInfo) {744	w.Sync(pkgbits.SyncObject)745	if w.Version().Has(pkgbits.DerivedFuncInstance) {746		w.Bool(false)747	}748	w.Reloc(pkgbits.SectionObj, info.idx)749750	w.Len(len(info.explicits))751	for _, info := range info.explicits {752		w.typInfo(info)753	}754}755756// objInstIdx returns the indices for an object and a corresponding757// list of type arguments used to instantiate it, adding them to the758// export data as needed.759func (pw *pkgWriter) objInstIdx(obj types2.Object, explicits []types2.Type, dict *writerDict) objInfo {760	explicitInfos := make([]typeInfo, len(explicits))761	for i := range explicitInfos {762		explicitInfos[i] = pw.typIdx(explicits[i], dict)763	}764	return objInfo{idx: pw.objIdx(obj), explicits: explicitInfos}765}766767// objIdx returns the index for the given Object, adding it to the768// export data as needed.769func (pw *pkgWriter) objIdx(obj types2.Object) index {770	// TODO(mdempsky): Validate that obj is a global object (or a local771	// defined type, which we hoist to global scope anyway).772773	if idx, ok := pw.objsIdx[obj]; ok {774		return idx775	}776777	dict := &writerDict{778		derivedIdx: make(map[types2.Type]index),779	}780781	if isDefinedType(obj) && obj.Pkg() == pw.curpkg {782		decl, ok := pw.typDecls[obj.(*types2.TypeName)]783		if !ok {784			base.Fatalf("%v not in pw.typDecls", obj.(*types2.TypeName))785		}786		dict.implicits = decl.implicits787	}788789	if isGenericMethod(obj.Type()) {790		dict.receivers = asTypeParamSlice(obj.Type().(*types2.Signature).RecvTypeParams())791	}792793	// We encode objects into 4 elements across different sections, all794	// sharing the same index:795	//796	// - RelocName has just the object's qualified name (i.e.,797	//   Object.Pkg and Object.Name) and the CodeObj indicating what798	//   specific type of Object it is (Var, Func, etc).799	//800	// - RelocObj has the remaining public details about the object,801	//   relevant to go/types importers.802	//803	// - RelocObjExt has additional private details about the object,804	//   which are only relevant to cmd/compile itself. This is805	//   separated from RelocObj so that go/types importers are806	//   unaffected by internal compiler changes.807	//808	// - RelocObjDict has public details about the object's type809	//   parameters and derived type's used by the object. This is810	//   separated to facilitate the eventual introduction of811	//   shape-based stenciling.812	//813	// TODO(mdempsky): Re-evaluate whether RelocName still makes sense814	// to keep separate from RelocObj.815816	w := pw.newWriter(pkgbits.SectionObj, pkgbits.SyncObject1)817	wext := pw.newWriter(pkgbits.SectionObjExt, pkgbits.SyncObject1)818	wname := pw.newWriter(pkgbits.SectionName, pkgbits.SyncObject1)819	wdict := pw.newWriter(pkgbits.SectionObjDict, pkgbits.SyncObject1)820821	pw.objsIdx[obj] = w.Idx // break cycles822	assert(wext.Idx == w.Idx)823	assert(wname.Idx == w.Idx)824	assert(wdict.Idx == w.Idx)825826	w.dict = dict827	wext.dict = dict828829	code := w.doObj(wext, obj)830	w.Flush()831	wext.Flush()832833	wname.qualifiedIdent(obj)834	wname.Code(code)835	wname.Flush()836837	wdict.objDict(obj, w.dict)838	wdict.Flush()839840	return w.Idx841}842843// doObj writes the RelocObj definition for obj to w, and the844// RelocObjExt definition to wext.845func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {846	if obj.Pkg() != w.p.curpkg {847		return pkgbits.ObjStub848	}849850	switch obj := obj.(type) {851	default:852		w.p.unexpected("object", obj)853		panic("unreachable")854855	case *types2.Const:856		w.pos(obj)857		w.typ(obj.Type())858		w.Value(obj.Val())859		return pkgbits.ObjConst860861	case *types2.Func:862		if base.Flag.LowerH > 0 {863			// Unified IR panics are the worst; this is a huge help in debugging them.864			defer func() {865				if p := recover(); p != nil {866					fmt.Printf("Intercepted unified IR writer panic for function %s, repanicking", obj.FullName())867					panic(p)868				}869			}()870		}871		decl, ok := w.p.funDecls[obj]872		assert(ok)873		sig := obj.Type().(*types2.Signature)874875		w.pos(obj)876		if isGenericMethod(sig) {877			w.Bool(true) // generic method878879			w.selector(obj)880			w.typeParamNames(sig.RecvTypeParams())881			w.param(sig.Recv())882		} else {883			if w.Version().Has(pkgbits.GenericMethods) {884				w.Bool(false) // function885			}886		}887		w.typeParamNames(sig.TypeParams())888		w.signature(sig)889		w.pos(decl)890		wext.funcExt(obj)891		return pkgbits.ObjFunc892893	case *types2.TypeName:894		if obj.IsAlias() {895			w.pos(obj)896			rhs := obj.Type()897			var tparams *types2.TypeParamList898			if alias, ok := rhs.(*types2.Alias); ok { // materialized alias899				assert(alias.TypeArgs() == nil)900				tparams = alias.TypeParams()901				rhs = alias.Rhs()902			}903			if w.Version().Has(pkgbits.AliasTypeParamNames) {904				w.typeParamNames(tparams)905			}906			assert(w.Version().Has(pkgbits.AliasTypeParamNames) || tparams.Len() == 0)907			w.typ(rhs)908			return pkgbits.ObjAlias909		}910911		named := obj.Type().(*types2.Named)912		assert(named.TypeArgs() == nil)913914		w.pos(obj)915		w.typeParamNames(named.TypeParams())916		wext.typeExt(obj)917		w.typ(named.Underlying())918919		// separate generic and non-generic methods920		var methods, gmethods []*types2.Func921		for i := range named.NumMethods() {922			m := named.Method(i)923			if isGenericMethod(m.Type()) {924				gmethods = append(gmethods, m)925			} else {926				methods = append(methods, m)927			}928		}929		// encode non-generic methods inline930		w.Len(len(methods))931		for _, m := range methods {932			w.method(wext, m)933		}934		if len(gmethods) > 0 {935			assert(w.Version().Has(pkgbits.GenericMethods))936		}937		// encode a pointer to each generic method938		if w.Version().Has(pkgbits.GenericMethods) {939			w.Len(len(gmethods))940			for _, m := range gmethods {941				w.Reloc(pkgbits.SectionObj, w.p.objIdx(m))942			}943		}944945		return pkgbits.ObjType946947	case *types2.Var:948		w.pos(obj)949		w.typ(obj.Type())950		wext.varExt(obj)951		return pkgbits.ObjVar952	}953}954955// objDict writes the dictionary needed for reading the given object.956func (w *writer) objDict(obj types2.Object, dict *writerDict) {957	// TODO(mdempsky): Split objDict into multiple entries? reader.go958	// doesn't care about the type parameter bounds, and reader2.go959	// doesn't care about referenced functions.960961	w.dict = dict // TODO(mdempsky): This is a bit sketchy.962	w.Len(len(dict.implicits))963964	rtparams := objRecvTypeParams(obj)965	tparams := objTypeParams(obj)966967	if w.Version().Has(pkgbits.GenericMethods) {968		w.Len(len(rtparams))969	} else {970		assert(len(rtparams) == 0)971	}972	w.Len(len(tparams))973974	for _, rtparam := range rtparams {975		w.typ(rtparam.Constraint())976	}977	for _, tparam := range tparams {978		w.typ(tparam.Constraint())979	}980981	nderived := len(dict.derived)982	w.Len(nderived)983	for _, typ := range dict.derived {984		w.Reloc(pkgbits.SectionType, typ.idx)985		if w.Version().Has(pkgbits.DerivedInfoNeeded) {986			w.Bool(false)987		}988	}989990	// Write runtime dictionary information.991	//992	// N.B., the go/types importer reads up to the section, but doesn't993	// read any further, so it's safe to change. (See TODO above.)994995	// For each type parameter, write out whether the constraint is a996	// basic interface. This is used to determine how aggressively we997	// can shape corresponding type arguments.998	//999	// This is somewhat redundant with writing out the full type1000	// parameter constraints above, but the compiler currently skips1001	// over those. Also, we don't care about the *declared* constraints,1002	// but how the type parameters are actually *used*. E.g., if a type1003	// parameter is constrained to `int | uint` but then never used in1004	// arithmetic/conversions/etc, we could shape those together.1005	for _, implicit := range dict.implicits {1006		w.Bool(implicit.Underlying().(*types2.Interface).IsMethodSet())1007	}1008	for _, rtparam := range rtparams {1009		w.Bool(rtparam.Underlying().(*types2.Interface).IsMethodSet())1010	}1011	for _, tparam := range tparams {1012		w.Bool(tparam.Underlying().(*types2.Interface).IsMethodSet())1013	}10141015	w.Len(len(dict.typeParamMethodExprs))1016	for _, info := range dict.typeParamMethodExprs {1017		w.Len(info.typeParamIdx)1018		w.selectorInfo(info.methodInfo)1019	}10201021	w.Len(len(dict.subdicts))1022	for _, info := range dict.subdicts {1023		w.objInfo(info)1024	}10251026	w.Len(len(dict.rtypes))1027	for _, info := range dict.rtypes {1028		w.typInfo(info)1029	}10301031	w.Len(len(dict.itabs))1032	for _, info := range dict.itabs {1033		w.typInfo(info.typ)1034		w.typInfo(info.iface)1035	}10361037	assert(len(dict.derived) == nderived)1038}10391040func (w *writer) typeParamNames(tparams *types2.TypeParamList) {1041	w.Sync(pkgbits.SyncTypeParamNames)10421043	ntparams := tparams.Len()1044	for i := 0; i < ntparams; i++ {1045		tparam := tparams.At(i).Obj()1046		w.pos(tparam)1047		w.localIdent(tparam)1048	}1049}10501051func (w *writer) method(wext *writer, meth *types2.Func) {1052	decl, ok := w.p.funDecls[meth]1053	assert(ok)1054	sig := meth.Type().(*types2.Signature)10551056	w.Sync(pkgbits.SyncMethod)1057	w.pos(meth)1058	w.selector(meth)1059	w.typeParamNames(sig.RecvTypeParams())1060	w.param(sig.Recv())1061	w.signature(sig)10621063	w.pos(decl) // XXX: Hack to workaround linker limitations.1064	wext.funcExt(meth)1065}10661067// qualifiedIdent writes out the name of an object typically declared at package1068// scope. It's also used to refer to generic methods and locally defined types.1069func (w *writer) qualifiedIdent(obj types2.Object) {1070	w.Sync(pkgbits.SyncSym)10711072	name := obj.Name()1073	if isDefinedType(obj) && obj.Pkg() == w.p.curpkg {1074		decl, ok := w.p.typDecls[obj.(*types2.TypeName)]1075		assert(ok)1076		if decl.gen != 0 {1077			// For local defined types, we embed a scope-disambiguation1078			// number directly into their name. types.SplitVargenSuffix then1079			// knows to look for this.1080			//1081			// TODO(mdempsky): Find a better solution; this is terrible.1082			name = fmt.Sprintf("%s·%v", name, decl.gen)1083		}1084	}10851086	// Generic methods are promoted to objects and thus need qualified identifiers.1087	// They must be contextualized by their defining type.1088	if isGenericMethod(obj.Type()) {1089		recv := obj.Type().(*types2.Signature).Recv().Type()1090		fstr := "%s.%s"1091		if _, ok := recv.(*types2.Pointer); ok {1092			fstr = "(*%s).%s"1093		}1094		name = fmt.Sprintf(fstr, types2.Unalias(deref2(recv)).(*types2.Named).Obj().Name(), name)1095	}10961097	w.pkg(obj.Pkg())1098	w.String(name)1099}11001101// TODO(mdempsky): We should be able to omit pkg from both localIdent1102// and selector, because they should always be known from context.1103// However, past frustrations with this optimization in iexport make1104// me a little nervous to try it again.11051106// localIdent writes the name of a locally declared object (i.e.,1107// objects that can only be accessed by non-qualified name, within the1108// context of a particular function).1109func (w *writer) localIdent(obj types2.Object) {1110	assert(!isGlobal(obj))1111	w.Sync(pkgbits.SyncLocalIdent)1112	w.pkg(obj.Pkg())1113	w.String(obj.Name())1114}11151116// selector writes the name of a field or method (i.e., objects that1117// can only be accessed using selector expressions).1118func (w *writer) selector(obj types2.Object) {1119	w.selectorInfo(w.p.selectorIdx(obj))1120}11211122func (w *writer) selectorInfo(info selectorInfo) {1123	w.Sync(pkgbits.SyncSelector)1124	w.pkgRef(info.pkgIdx)1125	w.StringRef(info.nameIdx)1126}11271128func (pw *pkgWriter) selectorIdx(obj types2.Object) selectorInfo {1129	pkgIdx := pw.pkgIdx(obj.Pkg())1130	nameIdx := pw.StringIdx(obj.Name())1131	return selectorInfo{pkgIdx: pkgIdx, nameIdx: nameIdx}1132}11331134// @@@ Compiler extensions11351136func (w *writer) funcExt(obj *types2.Func) {1137	decl, ok := w.p.funDecls[obj]1138	assert(ok)11391140	// TODO(mdempsky): Extend these pragma validation flags to account1141	// for generics. E.g., linkname probably doesn't make sense at1142	// least.11431144	pragma := asPragmaFlag(decl.Pragma)1145	if pragma&ir.Systemstack != 0 && pragma&ir.Nosplit != 0 {1146		w.p.errorf(decl, "go:nosplit and go:systemstack cannot be combined")1147	}1148	wi := asWasmImport(decl.Pragma)1149	we := asWasmExport(decl.Pragma)11501151	if decl.Body != nil {1152		if pragma&ir.Noescape != 0 {1153			w.p.errorf(decl, "can only use //go:noescape with external func implementations")1154		}1155		if wi != nil {1156			w.p.errorf(decl, "can only use //go:wasmimport with external func implementations")1157		}1158		if (pragma&ir.UintptrKeepAlive != 0 && pragma&ir.UintptrEscapes == 0) && pragma&ir.Nosplit == 0 {1159			// Stack growth can't handle uintptr arguments that may1160			// be pointers (as we don't know which are pointers1161			// when creating the stack map). Thus uintptrkeepalive1162			// functions (and all transitive callees) must be1163			// nosplit.1164			//1165			// N.B. uintptrescapes implies uintptrkeepalive but it1166			// is OK since the arguments must escape to the heap.1167			//1168			// TODO(prattmic): Add recursive nosplit check of callees.1169			// TODO(prattmic): Functions with no body (i.e.,1170			// assembly) must also be nosplit, but we can't check1171			// that here.1172			w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit")1173		}1174	} else {1175		if base.Flag.Complete || decl.Name.Value == "init" {1176			// Linknamed functions are allowed to have no body. Hopefully1177			// the linkname target has a body. See issue 23311.1178			// Wasmimport functions are also allowed to have no body.1179			if _, ok := w.p.linknames[obj]; !ok && wi == nil {1180				w.p.errorf(decl, "missing function body")1181			}1182		}1183	}11841185	sig, block := obj.Type().(*types2.Signature), decl.Body1186	body, closureVars := w.p.bodyIdx(sig, block, w.dict)1187	if len(closureVars) > 0 {1188		fmt.Fprintln(os.Stderr, "CLOSURE", closureVars)1189	}1190	assert(len(closureVars) == 0)11911192	w.Sync(pkgbits.SyncFuncExt)1193	w.pragmaFlag(pragma)1194	w.linkname(obj)11951196	if buildcfg.GOARCH == "wasm" {1197		if wi != nil {1198			w.String(wi.Module)1199			w.String(wi.Name)1200		} else {1201			w.String("")1202			w.String("")1203		}1204		if we != nil {1205			w.String(we.Name)1206		} else {1207			w.String("")1208		}1209	}12101211	w.Bool(false) // stub extension1212	w.Reloc(pkgbits.SectionBody, body)1213	w.Sync(pkgbits.SyncEOF)1214}12151216func (w *writer) typeExt(obj *types2.TypeName) {1217	decl, ok := w.p.typDecls[obj]1218	assert(ok)12191220	w.Sync(pkgbits.SyncTypeExt)12211222	w.pragmaFlag(asPragmaFlag(decl.Pragma))12231224	// No LSym.SymIdx info yet.1225	w.Int64(-1)1226	w.Int64(-1)1227}12281229func (w *writer) varExt(obj *types2.Var) {1230	w.Sync(pkgbits.SyncVarExt)1231	w.linkname(obj)1232}12331234func (w *writer) linkname(obj types2.Object) {1235	w.Sync(pkgbits.SyncLinkname)1236	w.Int64(-1)1237	info := w.p.linknames[obj]1238	w.String(info.remote)1239	w.Bool(info.std)1240}12411242func (w *writer) pragmaFlag(p ir.PragmaFlag) {1243	w.Sync(pkgbits.SyncPragma)1244	w.Int(int(p))1245}12461247// @@@ Function bodies12481249// bodyIdx returns the index for the given function body (specified by1250// block), adding it to the export data1251func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx index, closureVars []posVar) {1252	w := pw.newWriter(pkgbits.SectionBody, pkgbits.SyncFuncBody)1253	w.sig = sig1254	w.dict = dict12551256	w.declareParams(sig)1257	if w.Bool(block != nil) {1258		w.stmts(block.List)1259		w.pos(block.Rbrace)1260	}12611262	return w.Flush(), w.closureVars1263}12641265func (w *writer) declareParams(sig *types2.Signature) {1266	addLocals := func(params *types2.Tuple) {1267		for i := 0; i < params.Len(); i++ {1268			w.addLocal(params.At(i))1269		}1270	}12711272	if recv := sig.Recv(); recv != nil {1273		w.addLocal(recv)1274	}1275	addLocals(sig.Params())1276	addLocals(sig.Results())1277}12781279// addLocal records the declaration of a new local variable.1280func (w *writer) addLocal(obj *types2.Var) {1281	idx := len(w.localsIdx)12821283	w.Sync(pkgbits.SyncAddLocal)1284	if w.p.SyncMarkers() {1285		w.Int(idx)1286	}1287	w.varDictIndex(obj)12881289	if w.localsIdx == nil {1290		w.localsIdx = make(map[*types2.Var]int)1291	}1292	w.localsIdx[obj] = idx1293}12941295// useLocal writes a reference to the given local or free variable1296// into the bitstream.1297func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) {1298	w.Sync(pkgbits.SyncUseObjLocal)12991300	if idx, ok := w.localsIdx[obj]; w.Bool(ok) {1301		w.Len(idx)1302		return1303	}13041305	idx, ok := w.closureVarsIdx[obj]1306	if !ok {1307		if w.closureVarsIdx == nil {1308			w.closureVarsIdx = make(map[*types2.Var]int)1309		}1310		idx = len(w.closureVars)1311		w.closureVars = append(w.closureVars, posVar{pos, obj})1312		w.closureVarsIdx[obj] = idx1313	}1314	w.Len(idx)1315}13161317func (w *writer) openScope(pos syntax.Pos) {1318	w.Sync(pkgbits.SyncOpenScope)1319	w.pos(pos)1320}13211322func (w *writer) closeScope(pos syntax.Pos) {1323	w.Sync(pkgbits.SyncCloseScope)1324	w.pos(pos)1325	w.closeAnotherScope()1326}13271328func (w *writer) closeAnotherScope() {1329	w.Sync(pkgbits.SyncCloseAnotherScope)1330}13311332// @@@ Statements13331334// stmt writes the given statement into the function body bitstream.1335func (w *writer) stmt(stmt syntax.Stmt) {1336	var stmts []syntax.Stmt1337	if stmt != nil {1338		stmts = []syntax.Stmt{stmt}1339	}1340	w.stmts(stmts)1341}13421343func (w *writer) stmts(stmts []syntax.Stmt) {1344	dead := false1345	w.Sync(pkgbits.SyncStmts)1346	var lastLabel = -11347	for i, stmt := range stmts {1348		if _, ok := stmt.(*syntax.LabeledStmt); ok {1349			lastLabel = i1350		}1351	}1352	for i, stmt := range stmts {1353		if dead && i > lastLabel {1354			// Any statements after a terminating and last label statement are safe to omit.1355			// Otherwise, code after label statement may refer to dead stmts between terminating1356			// and label statement, see issue #65593.1357			if _, ok := stmt.(*syntax.LabeledStmt); !ok {1358				continue1359			}1360		}1361		w.stmt1(stmt)1362		dead = w.p.terminates(stmt)1363	}1364	w.Code(stmtEnd)1365	w.Sync(pkgbits.SyncStmtsEnd)1366}13671368func (w *writer) stmt1(stmt syntax.Stmt) {1369	switch stmt := stmt.(type) {1370	default:1371		w.p.unexpected("statement", stmt)13721373	case nil, *syntax.EmptyStmt:1374		return13751376	case *syntax.AssignStmt:1377		switch {1378		case stmt.Rhs == nil:1379			w.Code(stmtIncDec)1380			w.op(binOps[stmt.Op])1381			w.expr(stmt.Lhs)1382			w.pos(stmt)13831384		case stmt.Op != 0 && stmt.Op != syntax.Def:1385			w.Code(stmtAssignOp)1386			w.op(binOps[stmt.Op])1387			w.expr(stmt.Lhs)1388			w.pos(stmt)13891390			var typ types2.Type1391			if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr {1392				typ = w.p.typeOf(stmt.Lhs)1393			}1394			w.implicitConvExpr(typ, stmt.Rhs)13951396		default:1397			w.assignStmt(stmt, stmt.Lhs, stmt.Rhs)1398		}13991400	case *syntax.BlockStmt:1401		w.Code(stmtBlock)1402		w.blockStmt(stmt)14031404	case *syntax.BranchStmt:1405		w.Code(stmtBranch)1406		w.pos(stmt)1407		var op ir.Op1408		switch stmt.Tok {1409		case syntax.Break:1410			op = ir.OBREAK1411		case syntax.Continue:1412			op = ir.OCONTINUE1413		case syntax.Fallthrough:1414			op = ir.OFALL1415		case syntax.Goto:1416			op = ir.OGOTO1417		}1418		w.op(op)1419		w.optLabel(stmt.Label)14201421	case *syntax.CallStmt:1422		w.Code(stmtCall)1423		w.pos(stmt)1424		var op ir.Op1425		switch stmt.Tok {1426		case syntax.Defer:1427			op = ir.ODEFER1428		case syntax.Go:1429			op = ir.OGO1430		}1431		w.op(op)1432		w.expr(stmt.Call)1433		if stmt.Tok == syntax.Defer {1434			w.optExpr(stmt.DeferAt)1435		}14361437	case *syntax.DeclStmt:1438		for _, decl := range stmt.DeclList {1439			w.declStmt(decl)1440		}14411442	case *syntax.ExprStmt:1443		w.Code(stmtExpr)1444		w.expr(stmt.X)14451446	case *syntax.ForStmt:1447		w.Code(stmtFor)1448		w.forStmt(stmt)14491450	case *syntax.IfStmt:1451		w.Code(stmtIf)1452		w.ifStmt(stmt)14531454	case *syntax.LabeledStmt:1455		w.Code(stmtLabel)1456		w.pos(stmt)1457		w.label(stmt.Label)1458		w.stmt1(stmt.Stmt)14591460	case *syntax.ReturnStmt:1461		w.Code(stmtReturn)1462		w.pos(stmt)14631464		resultTypes := w.sig.Results()1465		dstType := func(i int) types2.Type {1466			return resultTypes.At(i).Type()1467		}1468		w.multiExpr(stmt, dstType, syntax.UnpackListExpr(stmt.Results))14691470	case *syntax.SelectStmt:1471		w.Code(stmtSelect)1472		w.selectStmt(stmt)14731474	case *syntax.SendStmt:1475		chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan)14761477		w.Code(stmtSend)1478		w.pos(stmt)1479		w.expr(stmt.Chan)1480		w.implicitConvExpr(chanType.Elem(), stmt.Value)14811482	case *syntax.SwitchStmt:1483		w.Code(stmtSwitch)1484		w.switchStmt(stmt)1485	}1486}14871488func (w *writer) assignList(expr syntax.Expr) {1489	exprs := syntax.UnpackListExpr(expr)1490	w.Len(len(exprs))14911492	for _, expr := range exprs {1493		w.assign(expr)1494	}1495}14961497func (w *writer) assign(expr syntax.Expr) {1498	expr = syntax.Unparen(expr)14991500	if name, ok := expr.(*syntax.Name); ok {1501		if name.Value == "_" {1502			w.Code(assignBlank)1503			return1504		}15051506		if obj, ok := w.p.info.Defs[name]; ok {1507			obj := obj.(*types2.Var)15081509			w.Code(assignDef)1510			w.pos(obj)1511			w.localIdent(obj)1512			w.typ(obj.Type())15131514			// TODO(mdempsky): Minimize locals index size by deferring1515			// this until the variables actually come into scope.1516			w.addLocal(obj)1517			return1518		}1519	}15201521	w.Code(assignExpr)1522	w.expr(expr)1523}15241525func (w *writer) declStmt(decl syntax.Decl) {1526	switch decl := decl.(type) {1527	default:1528		w.p.unexpected("declaration", decl)15291530	case *syntax.ConstDecl, *syntax.TypeDecl:15311532	case *syntax.VarDecl:1533		w.assignStmt(decl, namesAsExpr(decl.NameList), decl.Values)1534	}1535}15361537// assignStmt writes out an assignment for "lhs = rhs".1538func (w *writer) assignStmt(pos poser, lhs0, rhs0 syntax.Expr) {1539	lhs := syntax.UnpackListExpr(lhs0)1540	rhs := syntax.UnpackListExpr(rhs0)15411542	w.Code(stmtAssign)1543	w.pos(pos)15441545	// As if w.assignList(lhs0).1546	w.Len(len(lhs))1547	for _, expr := range lhs {1548		w.assign(expr)1549	}15501551	dstType := func(i int) types2.Type {1552		dst := lhs[i]15531554		// Finding dstType is somewhat involved, because for VarDecl1555		// statements, the Names are only added to the info.{Defs,Uses}1556		// maps, not to info.Types.1557		if name, ok := syntax.Unparen(dst).(*syntax.Name); ok {1558			if name.Value == "_" {1559				return nil // ok: no implicit conversion1560			} else if def, ok := w.p.info.Defs[name].(*types2.Var); ok {1561				return def.Type()1562			} else if use, ok := w.p.info.Uses[name].(*types2.Var); ok {1563				return use.Type()1564			} else {1565				w.p.fatalf(dst, "cannot find type of destination object: %v", dst)1566			}1567		}15681569		return w.p.typeOf(dst)1570	}15711572	w.multiExpr(pos, dstType, rhs)1573}15741575func (w *writer) blockStmt(stmt *syntax.BlockStmt) {1576	w.Sync(pkgbits.SyncBlockStmt)1577	w.openScope(stmt.Pos())1578	w.stmts(stmt.List)1579	w.closeScope(stmt.Rbrace)1580}15811582func (w *writer) forStmt(stmt *syntax.ForStmt) {1583	w.Sync(pkgbits.SyncForStmt)1584	w.openScope(stmt.Pos())15851586	if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) {1587		w.pos(rang)1588		w.assignList(rang.Lhs)1589		w.expr(rang.X)15901591		xtyp := w.p.typeOf(rang.X)1592		if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap {1593			w.rtype(xtyp)1594		}1595		{1596			lhs := syntax.UnpackListExpr(rang.Lhs)1597			assign := func(i int, src types2.Type) {1598				if i >= len(lhs) {1599					return1600				}1601				dst := syntax.Unparen(lhs[i])1602				if name, ok := dst.(*syntax.Name); ok && name.Value == "_" {1603					return1604				}16051606				var dstType types2.Type1607				if rang.Def {1608					// For `:=` assignments, the LHS names only appear in Defs,1609					// not Types (as used by typeOf).1610					dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type()1611				} else {1612					dstType = w.p.typeOf(dst)1613				}16141615				w.convRTTI(src, dstType)1616			}16171618			keyType, valueType := types2.RangeKeyVal(w.p.typeOf(rang.X))1619			assign(0, keyType)1620			assign(1, valueType)1621		}16221623	} else {1624		if stmt.Cond != nil && w.p.staticBool(&stmt.Cond) < 0 { // always false1625			stmt.Post = nil1626			stmt.Body.List = nil1627		}16281629		w.pos(stmt)1630		w.stmt(stmt.Init)1631		w.optExpr(stmt.Cond)1632		w.stmt(stmt.Post)1633	}16341635	w.blockStmt(stmt.Body)1636	w.Bool(w.distinctVars(stmt))1637	w.closeAnotherScope()1638}16391640func (w *writer) distinctVars(stmt *syntax.ForStmt) bool {1641	lv := base.Debug.LoopVar1642	fileVersion := w.p.info.FileVersions[stmt.Pos().FileBase()]1643	is122 := fileVersion == "" || version.Compare(fileVersion, "go1.22") >= 016441645	// Turning off loopvar for 1.22 is only possible with loopvarhash=qn1646	//1647	// Debug.LoopVar values to be preserved for 1.21 compatibility are 1 and 2,1648	// which are also set (=1) by GOEXPERIMENT=loopvar.  The knobs for turning on1649	// the new, unshared, loopvar behavior apply to versions less than 1.21 because1650	// (1) 1.21 also did that and (2) this is believed to be the likely use case;1651	// anyone checking to see if it affects their code will just run the GOEXPERIMENT1652	// but will not also update all their go.mod files to 1.21.1653	//1654	// -gcflags=-d=loopvar=3 enables logging for 1.22 but does not turn loopvar on for <= 1.21.16551656	return is122 || lv > 0 && lv != 31657}16581659func (w *writer) ifStmt(stmt *syntax.IfStmt) {1660	cond := w.p.staticBool(&stmt.Cond)16611662	w.Sync(pkgbits.SyncIfStmt)1663	w.openScope(stmt.Pos())1664	w.pos(stmt)1665	w.stmt(stmt.Init)1666	w.expr(stmt.Cond)1667	w.Int(cond)1668	if cond >= 0 {1669		w.blockStmt(stmt.Then)1670	} else {1671		w.pos(stmt.Then.Rbrace)1672	}1673	if cond <= 0 {1674		w.stmt(stmt.Else)1675	}1676	w.closeAnotherScope()1677}16781679func (w *writer) selectStmt(stmt *syntax.SelectStmt) {1680	w.Sync(pkgbits.SyncSelectStmt)16811682	w.pos(stmt)1683	w.Len(len(stmt.Body))1684	for i, clause := range stmt.Body {1685		if i > 0 {1686			w.closeScope(clause.Pos())1687		}1688		w.openScope(clause.Pos())16891690		w.pos(clause)1691		w.stmt(clause.Comm)1692		w.stmts(clause.Body)1693	}1694	if len(stmt.Body) > 0 {1695		w.closeScope(stmt.Rbrace)1696	}1697}16981699func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {1700	w.Sync(pkgbits.SyncSwitchStmt)17011702	w.openScope(stmt.Pos())1703	w.pos(stmt)1704	w.stmt(stmt.Init)17051706	var iface, tagType types2.Type1707	var tagTypeIsChan bool1708	if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) {1709		iface = w.p.typeOf(guard.X)17101711		w.pos(guard)1712		if tag := guard.Lhs; w.Bool(tag != nil) {1713			w.pos(tag)17141715			// Like w.localIdent, but we don't have a types2.Object.1716			w.Sync(pkgbits.SyncLocalIdent)1717			w.pkg(w.p.curpkg)1718			w.String(tag.Value)1719		}1720		w.expr(guard.X)1721	} else {1722		tag := stmt.Tag17231724		var tagValue constant.Value1725		if tag != nil {1726			tv := w.p.typeAndValue(tag)1727			tagType = tv.Type1728			tagValue = tv.Value1729			_, tagTypeIsChan = tagType.Underlying().(*types2.Chan)1730		} else {1731			tagType = types2.Typ[types2.Bool]1732			tagValue = constant.MakeBool(true)1733		}17341735		if tagValue != nil {1736			// If the switch tag has a constant value, look for a case1737			// clause that we always branch to.1738			func() {1739				var target *syntax.CaseClause1740			Outer:1741				for _, clause := range stmt.Body {1742					if clause.Cases == nil {1743						target = clause1744					}1745					for _, cas := range syntax.UnpackListExpr(clause.Cases) {1746						tv := w.p.typeAndValue(cas)1747						if tv.Value == nil {1748							return // non-constant case; give up1749						}1750						if constant.Compare(tagValue, token.EQL, tv.Value) {1751							target = clause1752							break Outer1753						}1754					}1755				}1756				// We've found the target clause, if any.17571758				if target != nil {1759					if hasFallthrough(target.Body) {1760						return // fallthrough is tricky; give up1761					}17621763					// Rewrite as single "default" case.1764					target.Cases = nil1765					stmt.Body = []*syntax.CaseClause{target}1766				} else {1767					stmt.Body = nil1768				}17691770				// Clear switch tag (i.e., replace with implicit "true").1771				tag = nil1772				stmt.Tag = nil1773				tagType = types2.Typ[types2.Bool]1774			}()1775		}17761777		// Walk is going to emit comparisons between the tag value and1778		// each case expression, and we want these comparisons to always1779		// have the same type. If there are any case values that can't be1780		// converted to the tag value's type, then convert everything to1781		// `any` instead.1782		//1783		// Except that we need to keep comparisons of channel values from1784		// being wrapped in any(). See issue #67190.17851786		if !tagTypeIsChan {1787		Outer:1788			for _, clause := range stmt.Body {1789				for _, cas := range syntax.UnpackListExpr(clause.Cases) {1790					if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) && (types2.IsInterface(casType) || types2.IsInterface(tagType)) {1791						tagType = types2.NewInterfaceType(nil, nil)1792						break Outer1793					}1794				}1795			}1796		}17971798		if w.Bool(tag != nil) {1799			w.implicitConvExpr(tagType, tag)1800		}1801	}18021803	w.Len(len(stmt.Body))1804	for i, clause := range stmt.Body {1805		if i > 0 {1806			w.closeScope(clause.Pos())1807		}1808		w.openScope(clause.Pos())18091810		w.pos(clause)18111812		cases := syntax.UnpackListExpr(clause.Cases)1813		if iface != nil {1814			w.Len(len(cases))1815			for _, cas := range cases {1816				if w.Bool(isNil(w.p, cas)) {1817					continue1818				}1819				w.exprType(iface, cas)1820			}1821		} else {1822			// As if w.exprList(clause.Cases),1823			// but with implicit conversions to tagType.18241825			w.Sync(pkgbits.SyncExprList)1826			w.Sync(pkgbits.SyncExprs)1827			w.Len(len(cases))1828			for _, cas := range cases {1829				typ := tagType1830				if tagTypeIsChan {1831					typ = nil1832				}1833				w.implicitConvExpr(typ, cas)1834			}1835		}18361837		if obj, ok := w.p.info.Implicits[clause]; ok {1838			// TODO(mdempsky): These pos details are quirkish, but also1839			// necessary so the variable's position is correct for DWARF1840			// scope assignment later. It would probably be better for us to1841			// instead just set the variable's DWARF scoping info earlier so1842			// we can give it the correct position information.1843			pos := clause.Pos()1844			if typs := syntax.UnpackListExpr(clause.Cases); len(typs) != 0 {1845				pos = typeExprEndPos(typs[len(typs)-1])1846			}1847			w.pos(pos)18481849			obj := obj.(*types2.Var)1850			w.typ(obj.Type())1851			w.addLocal(obj)1852		}18531854		w.stmts(clause.Body)1855	}1856	if len(stmt.Body) > 0 {1857		w.closeScope(stmt.Rbrace)1858	}18591860	w.closeScope(stmt.Rbrace)1861}18621863func (w *writer) label(label *syntax.Name) {1864	w.Sync(pkgbits.SyncLabel)18651866	// TODO(mdempsky): Replace label strings with dense indices.1867	w.String(label.Value)1868}18691870func (w *writer) optLabel(label *syntax.Name) {1871	w.Sync(pkgbits.SyncOptLabel)1872	if w.Bool(label != nil) {1873		w.label(label)1874	}1875}18761877// @@@ Expressions18781879// expr writes the given expression into the function body bitstream.1880func (w *writer) expr(expr syntax.Expr) {1881	base.Assertf(expr != nil, "missing expression")18821883	expr = syntax.Unparen(expr) // skip parens; unneeded after typecheck18841885	obj, inst := lookupObj(w.p, expr)1886	targs := asTypeSlice(inst.TypeArgs)18871888	if tv, ok := w.p.maybeTypeAndValue(expr); ok {1889		if tv.IsRuntimeHelper() {1890			if pkg := obj.Pkg(); pkg != nil && pkg.Name() == "runtime" {1891				objName := obj.Name()1892				w.Code(exprRuntimeBuiltin)1893				w.String(objName)1894				return1895			}1896		}18971898		if tv.IsType() {1899			w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr))1900		}19011902		if tv.Value != nil {1903			w.Code(exprConst)1904			w.pos(expr)1905			typ := idealType(tv)1906			assert(typ != nil)1907			w.typ(typ)1908			w.Value(tv.Value)1909			return1910		}19111912		if _, isNil := obj.(*types2.Nil); isNil {1913			w.Code(exprZero)1914			w.pos(expr)1915			w.typ(tv.Type)1916			return1917		}19181919		// With shape types (and particular pointer shaping), we may have1920		// an expression of type "go.shape.*uint8", but need to reshape it1921		// to another shape-identical type to allow use in field1922		// selection, indexing, etc.1923		if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) {1924			w.Code(exprReshape)1925			w.typ(typ)1926			// fallthrough1927		}1928	}19291930	if obj != nil {1931		if len(targs) != 0 {1932			obj := obj.(*types2.Func)19331934			w.Code(exprFuncInst)1935			w.pos(expr)1936			w.funcInst(obj, targs)1937			return1938		}19391940		if isGlobal(obj) {1941			w.Code(exprGlobal)1942			w.obj(obj, nil)1943			return1944		}19451946		obj := obj.(*types2.Var)1947		assert(!obj.IsField())19481949		w.Code(exprLocal)1950		w.useLocal(expr.Pos(), obj)1951		return1952	}19531954	switch expr := expr.(type) {1955	default:1956		w.p.unexpected("expression", expr)19571958	case *syntax.CompositeLit:1959		w.Code(exprCompLit)1960		w.compLit(expr)19611962	case *syntax.FuncLit:1963		w.Code(exprFuncLit)1964		w.funcLit(expr)19651966	case *syntax.SelectorExpr:1967		sel, ok := w.p.info.Selections[expr]1968		assert(ok)19691970		switch sel.Kind() {1971		default:1972			w.p.fatalf(expr, "unexpected selection kind: %v", sel.Kind())19731974		case types2.FieldVal:1975			w.Code(exprFieldVal)1976			w.expr(expr.X)1977			w.pos(expr)1978			w.selector(sel.Obj())19791980		case types2.MethodVal:1981			w.methVal(expr, sel)19821983		case types2.MethodExpr:1984			w.methExpr(expr, sel)1985		}19861987	case *syntax.IndexExpr:1988		// might be explicit instantiation of a generic method1989		if selector, ok := expr.X.(*syntax.SelectorExpr); ok {1990			if sel, ok := w.p.info.Selections[selector]; ok {1991				switch sel.Kind() {1992				default:1993					w.p.fatalf(selector, "unexpected selection kind: %v", sel.Kind())1994				case types2.FieldVal:1995					// not a method1996				case types2.MethodVal:1997					w.methVal(selector, sel)1998					return1999				case types2.MethodExpr:2000					w.methExpr(selector, sel)

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.