...

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

Documentation: cmd/compile/internal/importer

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

View as plain text