Source file src/cmd/compile/internal/testimporter/ureader.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // package testimporter implements reading of compiler-internal unified export
     6  // formats.
     7  package testimporter
     8  
     9  // TODO(mark): Remove fork in cmd/compile/internal/importer.
    10  
    11  import (
    12  	"cmd/compile/internal/base"
    13  	"cmd/compile/internal/syntax"
    14  	"cmd/compile/internal/types2"
    15  	"cmd/internal/src"
    16  	"internal/pkgbits"
    17  )
    18  
    19  type pkgReader struct {
    20  	pkgbits.PkgDecoder
    21  
    22  	ctxt        *types2.Context
    23  	imports     map[string]*types2.Package
    24  	enableAlias bool // whether to use aliases
    25  
    26  	posBases []*syntax.PosBase
    27  	pkgs     []*types2.Package
    28  	typs     []types2.Type
    29  }
    30  
    31  func ReadPackage(ctxt *types2.Context, imports map[string]*types2.Package, input pkgbits.PkgDecoder) *types2.Package {
    32  	pr := pkgReader{
    33  		PkgDecoder: input,
    34  
    35  		ctxt:        ctxt,
    36  		imports:     imports,
    37  		enableAlias: true,
    38  
    39  		posBases: make([]*syntax.PosBase, input.NumElems(pkgbits.SectionPosBase)),
    40  		pkgs:     make([]*types2.Package, input.NumElems(pkgbits.SectionPkg)),
    41  		typs:     make([]types2.Type, input.NumElems(pkgbits.SectionType)),
    42  	}
    43  
    44  	r := pr.newReader(pkgbits.SectionMeta, pkgbits.PublicRootIdx, pkgbits.SyncPublic)
    45  	pkg := r.pkg()
    46  
    47  	if r.Version().Has(pkgbits.HasInit) {
    48  		r.Bool()
    49  	}
    50  
    51  	for i, n := 0, r.Len(); i < n; i++ {
    52  		// As if r.obj(), but avoiding the Scope.Lookup call,
    53  		// to avoid eager loading of imports.
    54  		r.Sync(pkgbits.SyncObject)
    55  		if r.Version().Has(pkgbits.DerivedFuncInstance) {
    56  			assert(!r.Bool())
    57  		}
    58  		r.p.objIdx(r.Reloc(pkgbits.SectionObj))
    59  		assert(r.Len() == 0)
    60  	}
    61  
    62  	r.Sync(pkgbits.SyncEOF)
    63  
    64  	pkg.MarkComplete()
    65  	return pkg
    66  }
    67  
    68  type reader struct {
    69  	pkgbits.Decoder
    70  
    71  	p *pkgReader
    72  
    73  	dict    *readerDict
    74  	delayed []func()
    75  }
    76  
    77  type readerDict struct {
    78  	rtbounds []typeInfo
    79  	rtparams []*types2.TypeParam
    80  
    81  	tbounds []typeInfo
    82  	tparams []*types2.TypeParam
    83  
    84  	derived      []derivedInfo
    85  	derivedTypes []types2.Type
    86  }
    87  
    88  type readerTypeBound struct {
    89  	derived  bool
    90  	boundIdx int
    91  }
    92  
    93  func (pr *pkgReader) newReader(k pkgbits.SectionKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
    94  	return &reader{
    95  		Decoder: pr.NewDecoder(k, idx, marker),
    96  		p:       pr,
    97  	}
    98  }
    99  
   100  func (pr *pkgReader) tempReader(k pkgbits.SectionKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader {
   101  	return &reader{
   102  		Decoder: pr.TempDecoder(k, idx, marker),
   103  		p:       pr,
   104  	}
   105  }
   106  
   107  func (pr *pkgReader) retireReader(r *reader) {
   108  	pr.RetireDecoder(&r.Decoder)
   109  }
   110  
   111  // @@@ Positions
   112  
   113  func (r *reader) pos() syntax.Pos {
   114  	r.Sync(pkgbits.SyncPos)
   115  	if !r.Bool() {
   116  		return syntax.Pos{}
   117  	}
   118  
   119  	// TODO(mdempsky): Delta encoding.
   120  	posBase := r.posBase()
   121  	line := r.Uint()
   122  	col := r.Uint()
   123  	return syntax.MakePos(posBase, line, col)
   124  }
   125  
   126  func (r *reader) posBase() *syntax.PosBase {
   127  	return r.p.posBaseIdx(r.Reloc(pkgbits.SectionPosBase))
   128  }
   129  
   130  func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) *syntax.PosBase {
   131  	if b := pr.posBases[idx]; b != nil {
   132  		return b
   133  	}
   134  	var b *syntax.PosBase
   135  	{
   136  		r := pr.tempReader(pkgbits.SectionPosBase, idx, pkgbits.SyncPosBase)
   137  
   138  		filename := r.String()
   139  
   140  		if r.Bool() {
   141  			b = syntax.NewTrimmedFileBase(filename, true)
   142  		} else {
   143  			pos := r.pos()
   144  			line := r.Uint()
   145  			col := r.Uint()
   146  			b = syntax.NewLineBase(pos, filename, true, line, col)
   147  		}
   148  		pr.retireReader(r)
   149  	}
   150  
   151  	pr.posBases[idx] = b
   152  	return b
   153  }
   154  
   155  // @@@ Packages
   156  
   157  func (r *reader) pkg() *types2.Package {
   158  	r.Sync(pkgbits.SyncPkg)
   159  	return r.p.pkgIdx(r.Reloc(pkgbits.SectionPkg))
   160  }
   161  
   162  func (pr *pkgReader) pkgIdx(idx pkgbits.Index) *types2.Package {
   163  	// TODO(mdempsky): Consider using some non-nil pointer to indicate
   164  	// the universe scope, so we don't need to keep re-reading it.
   165  	if pkg := pr.pkgs[idx]; pkg != nil {
   166  		return pkg
   167  	}
   168  
   169  	pkg := pr.newReader(pkgbits.SectionPkg, idx, pkgbits.SyncPkgDef).doPkg()
   170  	pr.pkgs[idx] = pkg
   171  	return pkg
   172  }
   173  
   174  func (r *reader) doPkg() *types2.Package {
   175  	path := r.String()
   176  	switch path {
   177  	case "":
   178  		path = r.p.PkgPath()
   179  	case "builtin":
   180  		return nil // universe
   181  	case "unsafe":
   182  		return types2.Unsafe
   183  	}
   184  
   185  	if pkg := r.p.imports[path]; pkg != nil {
   186  		return pkg
   187  	}
   188  
   189  	name := r.String()
   190  	pkg := types2.NewPackage(path, name)
   191  	r.p.imports[path] = pkg
   192  
   193  	// TODO(mdempsky): The list of imported packages is important for
   194  	// go/types, but we could probably skip populating it for types2.
   195  	imports := make([]*types2.Package, r.Len())
   196  	for i := range imports {
   197  		imports[i] = r.pkg()
   198  	}
   199  	pkg.SetImports(imports)
   200  
   201  	return pkg
   202  }
   203  
   204  // @@@ Types
   205  
   206  func (r *reader) typ() types2.Type {
   207  	return r.p.typIdx(r.typInfo(), r.dict)
   208  }
   209  
   210  func (r *reader) typInfo() typeInfo {
   211  	r.Sync(pkgbits.SyncType)
   212  	if r.Bool() {
   213  		return typeInfo{idx: pkgbits.Index(r.Len()), derived: true}
   214  	}
   215  	return typeInfo{idx: r.Reloc(pkgbits.SectionType), derived: false}
   216  }
   217  
   218  func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types2.Type {
   219  	idx := info.idx
   220  	var where *types2.Type
   221  	if info.derived {
   222  		where = &dict.derivedTypes[idx]
   223  		idx = dict.derived[idx].idx
   224  	} else {
   225  		where = &pr.typs[idx]
   226  	}
   227  
   228  	if typ := *where; typ != nil {
   229  		return typ
   230  	}
   231  
   232  	var typ types2.Type
   233  	{
   234  		r := pr.tempReader(pkgbits.SectionType, idx, pkgbits.SyncTypeIdx)
   235  		r.dict = dict
   236  
   237  		typ = r.doTyp()
   238  		assert(typ != nil)
   239  		pr.retireReader(r)
   240  	}
   241  
   242  	// See comment in pkgReader.typIdx explaining how this happens.
   243  	if prev := *where; prev != nil {
   244  		return prev
   245  	}
   246  
   247  	*where = typ
   248  	return typ
   249  }
   250  
   251  func (r *reader) doTyp() (res types2.Type) {
   252  	switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag {
   253  	default:
   254  		base.FatalfAt(src.NoXPos, "unhandled type tag: %v", tag)
   255  		panic("unreachable")
   256  
   257  	case pkgbits.TypeBasic:
   258  		return types2.Typ[r.Len()]
   259  
   260  	case pkgbits.TypeNamed:
   261  		obj, targs := r.obj()
   262  		name := obj.(*types2.TypeName)
   263  		if len(targs) != 0 {
   264  			t, _ := types2.Instantiate(r.p.ctxt, name.Type(), targs, false)
   265  			return t
   266  		}
   267  		return name.Type()
   268  
   269  	case pkgbits.TypeTypeParam:
   270  		n := r.Len()
   271  		if n < len(r.dict.rtbounds) {
   272  			return r.dict.rtparams[n]
   273  		}
   274  		return r.dict.tparams[n-len(r.dict.rtbounds)]
   275  
   276  	case pkgbits.TypeArray:
   277  		len := int64(r.Uint64())
   278  		return types2.NewArray(r.typ(), len)
   279  	case pkgbits.TypeChan:
   280  		dir := types2.ChanDir(r.Len())
   281  		return types2.NewChan(dir, r.typ())
   282  	case pkgbits.TypeMap:
   283  		return types2.NewMap(r.typ(), r.typ())
   284  	case pkgbits.TypePointer:
   285  		return types2.NewPointer(r.typ())
   286  	case pkgbits.TypeSignature:
   287  		return r.signature(nil, nil, nil)
   288  	case pkgbits.TypeSlice:
   289  		return types2.NewSlice(r.typ())
   290  	case pkgbits.TypeStruct:
   291  		return r.structType()
   292  	case pkgbits.TypeInterface:
   293  		return r.interfaceType()
   294  	case pkgbits.TypeUnion:
   295  		return r.unionType()
   296  	}
   297  }
   298  
   299  func (r *reader) structType() *types2.Struct {
   300  	fields := make([]*types2.Var, r.Len())
   301  	var tags []string
   302  	for i := range fields {
   303  		pos := r.pos()
   304  		pkg, name := r.selector()
   305  		ftyp := r.typ()
   306  		tag := r.String()
   307  		embedded := r.Bool()
   308  
   309  		fields[i] = types2.NewField(pos, pkg, name, ftyp, embedded)
   310  		if tag != "" {
   311  			for len(tags) < i {
   312  				tags = append(tags, "")
   313  			}
   314  			tags = append(tags, tag)
   315  		}
   316  	}
   317  	return types2.NewStruct(fields, tags)
   318  }
   319  
   320  func (r *reader) unionType() *types2.Union {
   321  	terms := make([]*types2.Term, r.Len())
   322  	for i := range terms {
   323  		terms[i] = types2.NewTerm(r.Bool(), r.typ())
   324  	}
   325  	return types2.NewUnion(terms)
   326  }
   327  
   328  func (r *reader) interfaceType() *types2.Interface {
   329  	methods := make([]*types2.Func, r.Len())
   330  	embeddeds := make([]types2.Type, r.Len())
   331  	implicit := len(methods) == 0 && len(embeddeds) == 1 && r.Bool()
   332  
   333  	for i := range methods {
   334  		pos := r.pos()
   335  		pkg, name := r.selector()
   336  		mtyp := r.signature(nil, nil, nil)
   337  		methods[i] = types2.NewFunc(pos, pkg, name, mtyp)
   338  	}
   339  
   340  	for i := range embeddeds {
   341  		embeddeds[i] = r.typ()
   342  	}
   343  
   344  	iface := types2.NewInterfaceType(methods, embeddeds)
   345  	if implicit {
   346  		iface.MarkImplicit()
   347  	}
   348  	return iface
   349  }
   350  
   351  func (r *reader) signature(recv *types2.Var, rtparams, tparams []*types2.TypeParam) *types2.Signature {
   352  	r.Sync(pkgbits.SyncSignature)
   353  
   354  	params := r.params()
   355  	results := r.params()
   356  	variadic := r.Bool()
   357  
   358  	return types2.NewSignatureType(recv, rtparams, tparams, params, results, variadic)
   359  }
   360  
   361  func (r *reader) params() *types2.Tuple {
   362  	r.Sync(pkgbits.SyncParams)
   363  	params := make([]*types2.Var, r.Len())
   364  	for i := range params {
   365  		params[i] = r.param()
   366  	}
   367  	return types2.NewTuple(params...)
   368  }
   369  
   370  func (r *reader) param() *types2.Var {
   371  	r.Sync(pkgbits.SyncParam)
   372  
   373  	pos := r.pos()
   374  	pkg, name := r.localIdent()
   375  	typ := r.typ()
   376  
   377  	return types2.NewParam(pos, pkg, name, typ)
   378  }
   379  
   380  // @@@ Objects
   381  
   382  func (r *reader) obj() (types2.Object, []types2.Type) {
   383  	r.Sync(pkgbits.SyncObject)
   384  
   385  	if r.Version().Has(pkgbits.DerivedFuncInstance) {
   386  		assert(!r.Bool())
   387  	}
   388  
   389  	pkg, name := r.p.objIdx(r.Reloc(pkgbits.SectionObj))
   390  	obj := pkg.Scope().Lookup(name)
   391  
   392  	targs := make([]types2.Type, r.Len())
   393  	for i := range targs {
   394  		targs[i] = r.typ()
   395  	}
   396  
   397  	return obj, targs
   398  }
   399  
   400  func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) {
   401  	var objPkg *types2.Package
   402  	var objName string
   403  	var tag pkgbits.CodeObj
   404  	{
   405  		rname := pr.tempReader(pkgbits.SectionName, idx, pkgbits.SyncObject1)
   406  
   407  		objPkg, objName = rname.qualifiedIdent()
   408  		assert(objName != "")
   409  
   410  		tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj))
   411  		pr.retireReader(rname)
   412  	}
   413  
   414  	if tag == pkgbits.ObjStub {
   415  		base.Assertf(objPkg == nil || objPkg == types2.Unsafe, "unexpected stub package: %v", objPkg)
   416  		return objPkg, objName
   417  	}
   418  
   419  	objPkg.Scope().InsertLazy(objName, func() types2.Object {
   420  		dict := pr.objDictIdx(idx)
   421  
   422  		r := pr.newReader(pkgbits.SectionObj, idx, pkgbits.SyncObject1)
   423  		r.dict = dict
   424  
   425  		switch tag {
   426  		default:
   427  			panic("weird")
   428  
   429  		case pkgbits.ObjAlias:
   430  			pos := r.pos()
   431  			var tparams []*types2.TypeParam
   432  			if r.Version().Has(pkgbits.AliasTypeParamNames) {
   433  				tparams = r.typeParamNames(false, false)
   434  			}
   435  			typ := r.typ()
   436  			return newAliasTypeName(pr.enableAlias, pos, objPkg, objName, typ, tparams)
   437  
   438  		case pkgbits.ObjConst:
   439  			pos := r.pos()
   440  			typ := r.typ()
   441  			val := r.Value()
   442  			return types2.NewConst(pos, objPkg, objName, typ, val)
   443  
   444  		case pkgbits.ObjFunc:
   445  			pos := r.pos()
   446  			if r.Version().Has(pkgbits.GenericMethods) {
   447  				assert(!r.Bool()) // generic methods are read in their defining type
   448  			}
   449  			tparams := r.typeParamNames(false, false)
   450  			sig := r.signature(nil, nil, tparams)
   451  			return types2.NewFunc(pos, objPkg, objName, sig)
   452  
   453  		case pkgbits.ObjType:
   454  			pos := r.pos()
   455  
   456  			return types2.NewTypeNameLazy(pos, objPkg, objName, func(_ *types2.Named) ([]*types2.TypeParam, types2.Type, []*types2.Func, []func()) {
   457  				tparams := r.typeParamNames(true, false)
   458  
   459  				// TODO(mdempsky): Rewrite receiver types to underlying is an
   460  				// Interface? The go/types importer does this (I think because
   461  				// unit tests expected that), but cmd/compile doesn't care
   462  				// about it, so maybe we can avoid worrying about that here.
   463  				underlying := r.typ().Underlying()
   464  
   465  				methods := make([]*types2.Func, r.Len())
   466  				for i := range methods {
   467  					methods[i] = r.method(true)
   468  				}
   469  
   470  				if r.Version().Has(pkgbits.GenericMethods) {
   471  					for range r.Len() {
   472  						// Careful: objIdx is used to read in package-scoped declarations, which
   473  						// methods are not. Instead, decode it here. This makes it easier to
   474  						// associate it with the type and avoids the main objIdx loop.
   475  						idx := r.Reloc(pkgbits.SectionObj)
   476  
   477  						t := pr.tempReader(pkgbits.SectionObj, idx, pkgbits.SyncObject1)
   478  						t.dict = pr.objDictIdx(idx)
   479  
   480  						pos := t.pos()
   481  						assert(t.Bool()) // generic method
   482  						pkg, name := t.selector()
   483  						rtparams := t.typeParamNames(true, true)
   484  						recv := t.param()
   485  						tparams := t.typeParamNames(true, false)
   486  						sig := t.signature(recv, rtparams, tparams)
   487  
   488  						r.delayed = append(r.delayed, t.delayed...) // propagate before retiring
   489  
   490  						pr.retireReader(t)
   491  						methods = append(methods, types2.NewFunc(pos, pkg, name, sig))
   492  					}
   493  				}
   494  
   495  				return tparams, underlying, methods, r.delayed
   496  			})
   497  
   498  		case pkgbits.ObjVar:
   499  			pos := r.pos()
   500  			typ := r.typ()
   501  			return types2.NewVar(pos, objPkg, objName, typ)
   502  		}
   503  	})
   504  
   505  	return objPkg, objName
   506  }
   507  
   508  func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
   509  	var dict readerDict
   510  	{
   511  		r := pr.tempReader(pkgbits.SectionObjDict, idx, pkgbits.SyncObject1)
   512  
   513  		if implicits := r.Len(); implicits != 0 {
   514  			base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits)
   515  		}
   516  
   517  		nreceivers := 0
   518  		if r.Version().Has(pkgbits.GenericMethods) {
   519  			nreceivers = r.Len()
   520  		}
   521  		nexplicits := r.Len()
   522  
   523  		dict.rtbounds = make([]typeInfo, nreceivers)
   524  		for i := range dict.rtbounds {
   525  			dict.rtbounds[i] = r.typInfo()
   526  		}
   527  
   528  		dict.tbounds = make([]typeInfo, nexplicits)
   529  		for i := range dict.tbounds {
   530  			dict.tbounds[i] = r.typInfo()
   531  		}
   532  
   533  		dict.derived = make([]derivedInfo, r.Len())
   534  		dict.derivedTypes = make([]types2.Type, len(dict.derived))
   535  		for i := range dict.derived {
   536  			dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.SectionType)}
   537  			if r.Version().Has(pkgbits.DerivedInfoNeeded) {
   538  				assert(!r.Bool())
   539  			}
   540  		}
   541  
   542  		pr.retireReader(r)
   543  	}
   544  	// function references follow, but reader doesn't need those
   545  
   546  	return &dict
   547  }
   548  
   549  func (r *reader) typeParamNames(isLazy bool, isGenMeth bool) []*types2.TypeParam {
   550  	r.Sync(pkgbits.SyncTypeParamNames)
   551  
   552  	// Note: This code assumes there are no implicit type parameters.
   553  	// This is fine since it only reads exported declarations, which
   554  	// never have implicits.
   555  
   556  	var in []typeInfo
   557  	var out *[]*types2.TypeParam
   558  	if isGenMeth {
   559  		in = r.dict.rtbounds
   560  		out = &r.dict.rtparams
   561  	} else {
   562  		in = r.dict.tbounds
   563  		out = &r.dict.tparams
   564  	}
   565  
   566  	if len(in) == 0 {
   567  		return nil
   568  	}
   569  
   570  	// Careful: Type parameter lists may have cycles. To allow for this,
   571  	// we construct the type parameter list in two passes: first we
   572  	// create all the TypeNames and TypeParams, then we construct and
   573  	// set the bound type.
   574  
   575  	// We have to save tparams outside of the closure, because typeParamNames
   576  	// can be called multiple times with the same dictionary instance.
   577  	tparams := make([]*types2.TypeParam, len(in))
   578  	*out = tparams
   579  
   580  	for i := range in {
   581  		pos := r.pos()
   582  		pkg, name := r.localIdent()
   583  
   584  		tname := types2.NewTypeName(pos, pkg, name, nil)
   585  		tparams[i] = types2.NewTypeParam(tname, nil)
   586  	}
   587  
   588  	// Type parameters that are read by lazy loaders cannot have their
   589  	// constraints set eagerly; do them after loading (go.dev/issue/63285).
   590  	if isLazy {
   591  		// The reader dictionary will continue mutating before we have time
   592  		// to call delayed functions; make a local copy of the constraints.
   593  		types := make([]types2.Type, len(in))
   594  		for i, info := range in {
   595  			types[i] = r.p.typIdx(info, r.dict)
   596  		}
   597  
   598  		r.delayed = append(r.delayed, func() {
   599  			for i, typ := range types {
   600  				tparams[i].SetConstraint(typ)
   601  			}
   602  		})
   603  	} else {
   604  		for i, info := range in {
   605  			tparams[i].SetConstraint(r.p.typIdx(info, r.dict))
   606  		}
   607  	}
   608  
   609  	return tparams
   610  }
   611  
   612  func (r *reader) method(isLazy bool) *types2.Func {
   613  	r.Sync(pkgbits.SyncMethod)
   614  	pos := r.pos()
   615  	pkg, name := r.selector()
   616  
   617  	rtparams := r.typeParamNames(isLazy, false)
   618  	sig := r.signature(r.param(), rtparams, nil)
   619  
   620  	_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
   621  	return types2.NewFunc(pos, pkg, name, sig)
   622  }
   623  
   624  func (r *reader) qualifiedIdent() (*types2.Package, string) { return r.ident(pkgbits.SyncSym) }
   625  func (r *reader) localIdent() (*types2.Package, string)     { return r.ident(pkgbits.SyncLocalIdent) }
   626  func (r *reader) selector() (*types2.Package, string)       { return r.ident(pkgbits.SyncSelector) }
   627  
   628  func (r *reader) ident(marker pkgbits.SyncMarker) (*types2.Package, string) {
   629  	r.Sync(marker)
   630  	return r.pkg(), r.String()
   631  }
   632  
   633  // newAliasTypeName returns a new TypeName, with a materialized *types2.Alias if supported.
   634  func newAliasTypeName(aliases bool, pos syntax.Pos, pkg *types2.Package, name string, rhs types2.Type, tparams []*types2.TypeParam) *types2.TypeName {
   635  	// Copied from x/tools/internal/aliases.NewAlias via
   636  	// GOROOT/src/go/internal/gcimporter/ureader.go.
   637  	if aliases {
   638  		tname := types2.NewTypeName(pos, pkg, name, nil)
   639  		a := types2.NewAlias(tname, rhs) // form TypeName -> Alias cycle
   640  		a.SetTypeParams(tparams)
   641  		return tname
   642  	}
   643  	assert(len(tparams) == 0)
   644  	return types2.NewTypeName(pos, pkg, name, rhs)
   645  }
   646  

View as plain text