github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/go/internal/gcimporter/iexport.go (about)

     1  // Copyright 2019 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  // Indexed binary package export.
     6  // This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go;
     7  // see that file for specification of the format.
     8  
     9  package gcimporter
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/binary"
    14  	"fmt"
    15  	"go/ast"
    16  	"go/constant"
    17  	"go/token"
    18  	"go/types"
    19  	"io"
    20  	"math/big"
    21  	"reflect"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/jhump/golang-x-tools/internal/typeparams"
    27  )
    28  
    29  // Current bundled export format version. Increase with each format change.
    30  // 0: initial implementation
    31  const bundleVersion = 0
    32  
    33  // IExportData writes indexed export data for pkg to out.
    34  //
    35  // If no file set is provided, position info will be missing.
    36  // The package path of the top-level package will not be recorded,
    37  // so that calls to IImportData can override with a provided package path.
    38  func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
    39  	return iexportCommon(out, fset, false, iexportVersion, []*types.Package{pkg})
    40  }
    41  
    42  // IExportBundle writes an indexed export bundle for pkgs to out.
    43  func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
    44  	return iexportCommon(out, fset, true, iexportVersion, pkgs)
    45  }
    46  
    47  func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, version int, pkgs []*types.Package) (err error) {
    48  	if !debug {
    49  		defer func() {
    50  			if e := recover(); e != nil {
    51  				if ierr, ok := e.(internalError); ok {
    52  					err = ierr
    53  					return
    54  				}
    55  				// Not an internal error; panic again.
    56  				panic(e)
    57  			}
    58  		}()
    59  	}
    60  
    61  	p := iexporter{
    62  		fset:        fset,
    63  		version:     version,
    64  		allPkgs:     map[*types.Package]bool{},
    65  		stringIndex: map[string]uint64{},
    66  		declIndex:   map[types.Object]uint64{},
    67  		tparamNames: map[types.Object]string{},
    68  		typIndex:    map[types.Type]uint64{},
    69  	}
    70  	if !bundle {
    71  		p.localpkg = pkgs[0]
    72  	}
    73  
    74  	for i, pt := range predeclared() {
    75  		p.typIndex[pt] = uint64(i)
    76  	}
    77  	if len(p.typIndex) > predeclReserved {
    78  		panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
    79  	}
    80  
    81  	// Initialize work queue with exported declarations.
    82  	for _, pkg := range pkgs {
    83  		scope := pkg.Scope()
    84  		for _, name := range scope.Names() {
    85  			if ast.IsExported(name) {
    86  				p.pushDecl(scope.Lookup(name))
    87  			}
    88  		}
    89  
    90  		if bundle {
    91  			// Ensure pkg and its imports are included in the index.
    92  			p.allPkgs[pkg] = true
    93  			for _, imp := range pkg.Imports() {
    94  				p.allPkgs[imp] = true
    95  			}
    96  		}
    97  	}
    98  
    99  	// Loop until no more work.
   100  	for !p.declTodo.empty() {
   101  		p.doDecl(p.declTodo.popHead())
   102  	}
   103  
   104  	// Append indices to data0 section.
   105  	dataLen := uint64(p.data0.Len())
   106  	w := p.newWriter()
   107  	w.writeIndex(p.declIndex)
   108  
   109  	if bundle {
   110  		w.uint64(uint64(len(pkgs)))
   111  		for _, pkg := range pkgs {
   112  			w.pkg(pkg)
   113  			imps := pkg.Imports()
   114  			w.uint64(uint64(len(imps)))
   115  			for _, imp := range imps {
   116  				w.pkg(imp)
   117  			}
   118  		}
   119  	}
   120  	w.flush()
   121  
   122  	// Assemble header.
   123  	var hdr intWriter
   124  	if bundle {
   125  		hdr.uint64(bundleVersion)
   126  	}
   127  	hdr.uint64(uint64(p.version))
   128  	hdr.uint64(uint64(p.strings.Len()))
   129  	hdr.uint64(dataLen)
   130  
   131  	// Flush output.
   132  	io.Copy(out, &hdr)
   133  	io.Copy(out, &p.strings)
   134  	io.Copy(out, &p.data0)
   135  
   136  	return nil
   137  }
   138  
   139  // writeIndex writes out an object index. mainIndex indicates whether
   140  // we're writing out the main index, which is also read by
   141  // non-compiler tools and includes a complete package description
   142  // (i.e., name and height).
   143  func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
   144  	type pkgObj struct {
   145  		obj  types.Object
   146  		name string // qualified name; differs from obj.Name for type params
   147  	}
   148  	// Build a map from packages to objects from that package.
   149  	pkgObjs := map[*types.Package][]pkgObj{}
   150  
   151  	// For the main index, make sure to include every package that
   152  	// we reference, even if we're not exporting (or reexporting)
   153  	// any symbols from it.
   154  	if w.p.localpkg != nil {
   155  		pkgObjs[w.p.localpkg] = nil
   156  	}
   157  	for pkg := range w.p.allPkgs {
   158  		pkgObjs[pkg] = nil
   159  	}
   160  
   161  	for obj := range index {
   162  		name := w.p.exportName(obj)
   163  		pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
   164  	}
   165  
   166  	var pkgs []*types.Package
   167  	for pkg, objs := range pkgObjs {
   168  		pkgs = append(pkgs, pkg)
   169  
   170  		sort.Slice(objs, func(i, j int) bool {
   171  			return objs[i].name < objs[j].name
   172  		})
   173  	}
   174  
   175  	sort.Slice(pkgs, func(i, j int) bool {
   176  		return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j])
   177  	})
   178  
   179  	w.uint64(uint64(len(pkgs)))
   180  	for _, pkg := range pkgs {
   181  		w.string(w.exportPath(pkg))
   182  		w.string(pkg.Name())
   183  		w.uint64(uint64(0)) // package height is not needed for go/types
   184  
   185  		objs := pkgObjs[pkg]
   186  		w.uint64(uint64(len(objs)))
   187  		for _, obj := range objs {
   188  			w.string(obj.name)
   189  			w.uint64(index[obj.obj])
   190  		}
   191  	}
   192  }
   193  
   194  // exportName returns the 'exported' name of an object. It differs from
   195  // obj.Name() only for type parameters (see tparamExportName for details).
   196  func (p *iexporter) exportName(obj types.Object) (res string) {
   197  	if name := p.tparamNames[obj]; name != "" {
   198  		return name
   199  	}
   200  	return obj.Name()
   201  }
   202  
   203  type iexporter struct {
   204  	fset    *token.FileSet
   205  	out     *bytes.Buffer
   206  	version int
   207  
   208  	localpkg *types.Package
   209  
   210  	// allPkgs tracks all packages that have been referenced by
   211  	// the export data, so we can ensure to include them in the
   212  	// main index.
   213  	allPkgs map[*types.Package]bool
   214  
   215  	declTodo objQueue
   216  
   217  	strings     intWriter
   218  	stringIndex map[string]uint64
   219  
   220  	data0       intWriter
   221  	declIndex   map[types.Object]uint64
   222  	tparamNames map[types.Object]string // typeparam->exported name
   223  	typIndex    map[types.Type]uint64
   224  
   225  	indent int // for tracing support
   226  }
   227  
   228  func (p *iexporter) trace(format string, args ...interface{}) {
   229  	if !trace {
   230  		// Call sites should also be guarded, but having this check here allows
   231  		// easily enabling/disabling debug trace statements.
   232  		return
   233  	}
   234  	fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
   235  }
   236  
   237  // stringOff returns the offset of s within the string section.
   238  // If not already present, it's added to the end.
   239  func (p *iexporter) stringOff(s string) uint64 {
   240  	off, ok := p.stringIndex[s]
   241  	if !ok {
   242  		off = uint64(p.strings.Len())
   243  		p.stringIndex[s] = off
   244  
   245  		p.strings.uint64(uint64(len(s)))
   246  		p.strings.WriteString(s)
   247  	}
   248  	return off
   249  }
   250  
   251  // pushDecl adds n to the declaration work queue, if not already present.
   252  func (p *iexporter) pushDecl(obj types.Object) {
   253  	// Package unsafe is known to the compiler and predeclared.
   254  	assert(obj.Pkg() != types.Unsafe)
   255  
   256  	if _, ok := p.declIndex[obj]; ok {
   257  		return
   258  	}
   259  
   260  	p.declIndex[obj] = ^uint64(0) // mark obj present in work queue
   261  	p.declTodo.pushTail(obj)
   262  }
   263  
   264  // exportWriter handles writing out individual data section chunks.
   265  type exportWriter struct {
   266  	p *iexporter
   267  
   268  	data       intWriter
   269  	currPkg    *types.Package
   270  	prevFile   string
   271  	prevLine   int64
   272  	prevColumn int64
   273  }
   274  
   275  func (w *exportWriter) exportPath(pkg *types.Package) string {
   276  	if pkg == w.p.localpkg {
   277  		return ""
   278  	}
   279  	return pkg.Path()
   280  }
   281  
   282  func (p *iexporter) doDecl(obj types.Object) {
   283  	if trace {
   284  		p.trace("exporting decl %v (%T)", obj, obj)
   285  		p.indent++
   286  		defer func() {
   287  			p.indent--
   288  			p.trace("=> %s", obj)
   289  		}()
   290  	}
   291  	w := p.newWriter()
   292  	w.setPkg(obj.Pkg(), false)
   293  
   294  	switch obj := obj.(type) {
   295  	case *types.Var:
   296  		w.tag('V')
   297  		w.pos(obj.Pos())
   298  		w.typ(obj.Type(), obj.Pkg())
   299  
   300  	case *types.Func:
   301  		sig, _ := obj.Type().(*types.Signature)
   302  		if sig.Recv() != nil {
   303  			panic(internalErrorf("unexpected method: %v", sig))
   304  		}
   305  
   306  		// Function.
   307  		if typeparams.ForSignature(sig).Len() == 0 {
   308  			w.tag('F')
   309  		} else {
   310  			w.tag('G')
   311  		}
   312  		w.pos(obj.Pos())
   313  		// The tparam list of the function type is the declaration of the type
   314  		// params. So, write out the type params right now. Then those type params
   315  		// will be referenced via their type offset (via typOff) in all other
   316  		// places in the signature and function where they are used.
   317  		//
   318  		// While importing the type parameters, tparamList computes and records
   319  		// their export name, so that it can be later used when writing the index.
   320  		if tparams := typeparams.ForSignature(sig); tparams.Len() > 0 {
   321  			w.tparamList(obj.Name(), tparams, obj.Pkg())
   322  		}
   323  		w.signature(sig)
   324  
   325  	case *types.Const:
   326  		w.tag('C')
   327  		w.pos(obj.Pos())
   328  		w.value(obj.Type(), obj.Val())
   329  
   330  	case *types.TypeName:
   331  		t := obj.Type()
   332  
   333  		if tparam, ok := t.(*typeparams.TypeParam); ok {
   334  			w.tag('P')
   335  			w.pos(obj.Pos())
   336  			constraint := tparam.Constraint()
   337  			if p.version >= iexportVersionGo1_18 {
   338  				implicit := false
   339  				if iface, _ := constraint.(*types.Interface); iface != nil {
   340  					implicit = typeparams.IsImplicit(iface)
   341  				}
   342  				w.bool(implicit)
   343  			}
   344  			w.typ(constraint, obj.Pkg())
   345  			break
   346  		}
   347  
   348  		if obj.IsAlias() {
   349  			w.tag('A')
   350  			w.pos(obj.Pos())
   351  			w.typ(t, obj.Pkg())
   352  			break
   353  		}
   354  
   355  		// Defined type.
   356  		named, ok := t.(*types.Named)
   357  		if !ok {
   358  			panic(internalErrorf("%s is not a defined type", t))
   359  		}
   360  
   361  		if typeparams.ForNamed(named).Len() == 0 {
   362  			w.tag('T')
   363  		} else {
   364  			w.tag('U')
   365  		}
   366  		w.pos(obj.Pos())
   367  
   368  		if typeparams.ForNamed(named).Len() > 0 {
   369  			// While importing the type parameters, tparamList computes and records
   370  			// their export name, so that it can be later used when writing the index.
   371  			w.tparamList(obj.Name(), typeparams.ForNamed(named), obj.Pkg())
   372  		}
   373  
   374  		underlying := obj.Type().Underlying()
   375  		w.typ(underlying, obj.Pkg())
   376  
   377  		if types.IsInterface(t) {
   378  			break
   379  		}
   380  
   381  		n := named.NumMethods()
   382  		w.uint64(uint64(n))
   383  		for i := 0; i < n; i++ {
   384  			m := named.Method(i)
   385  			w.pos(m.Pos())
   386  			w.string(m.Name())
   387  			sig, _ := m.Type().(*types.Signature)
   388  
   389  			// Receiver type parameters are type arguments of the receiver type, so
   390  			// their name must be qualified before exporting recv.
   391  			if rparams := typeparams.RecvTypeParams(sig); rparams.Len() > 0 {
   392  				prefix := obj.Name() + "." + m.Name()
   393  				for i := 0; i < rparams.Len(); i++ {
   394  					rparam := rparams.At(i)
   395  					name := tparamExportName(prefix, rparam)
   396  					w.p.tparamNames[rparam.Obj()] = name
   397  				}
   398  			}
   399  			w.param(sig.Recv())
   400  			w.signature(sig)
   401  		}
   402  
   403  	default:
   404  		panic(internalErrorf("unexpected object: %v", obj))
   405  	}
   406  
   407  	p.declIndex[obj] = w.flush()
   408  }
   409  
   410  func (w *exportWriter) tag(tag byte) {
   411  	w.data.WriteByte(tag)
   412  }
   413  
   414  func (w *exportWriter) pos(pos token.Pos) {
   415  	if w.p.version >= iexportVersionPosCol {
   416  		w.posV1(pos)
   417  	} else {
   418  		w.posV0(pos)
   419  	}
   420  }
   421  
   422  func (w *exportWriter) posV1(pos token.Pos) {
   423  	if w.p.fset == nil {
   424  		w.int64(0)
   425  		return
   426  	}
   427  
   428  	p := w.p.fset.Position(pos)
   429  	file := p.Filename
   430  	line := int64(p.Line)
   431  	column := int64(p.Column)
   432  
   433  	deltaColumn := (column - w.prevColumn) << 1
   434  	deltaLine := (line - w.prevLine) << 1
   435  
   436  	if file != w.prevFile {
   437  		deltaLine |= 1
   438  	}
   439  	if deltaLine != 0 {
   440  		deltaColumn |= 1
   441  	}
   442  
   443  	w.int64(deltaColumn)
   444  	if deltaColumn&1 != 0 {
   445  		w.int64(deltaLine)
   446  		if deltaLine&1 != 0 {
   447  			w.string(file)
   448  		}
   449  	}
   450  
   451  	w.prevFile = file
   452  	w.prevLine = line
   453  	w.prevColumn = column
   454  }
   455  
   456  func (w *exportWriter) posV0(pos token.Pos) {
   457  	if w.p.fset == nil {
   458  		w.int64(0)
   459  		return
   460  	}
   461  
   462  	p := w.p.fset.Position(pos)
   463  	file := p.Filename
   464  	line := int64(p.Line)
   465  
   466  	// When file is the same as the last position (common case),
   467  	// we can save a few bytes by delta encoding just the line
   468  	// number.
   469  	//
   470  	// Note: Because data objects may be read out of order (or not
   471  	// at all), we can only apply delta encoding within a single
   472  	// object. This is handled implicitly by tracking prevFile and
   473  	// prevLine as fields of exportWriter.
   474  
   475  	if file == w.prevFile {
   476  		delta := line - w.prevLine
   477  		w.int64(delta)
   478  		if delta == deltaNewFile {
   479  			w.int64(-1)
   480  		}
   481  	} else {
   482  		w.int64(deltaNewFile)
   483  		w.int64(line) // line >= 0
   484  		w.string(file)
   485  		w.prevFile = file
   486  	}
   487  	w.prevLine = line
   488  }
   489  
   490  func (w *exportWriter) pkg(pkg *types.Package) {
   491  	// Ensure any referenced packages are declared in the main index.
   492  	w.p.allPkgs[pkg] = true
   493  
   494  	w.string(w.exportPath(pkg))
   495  }
   496  
   497  func (w *exportWriter) qualifiedIdent(obj types.Object) {
   498  	name := w.p.exportName(obj)
   499  
   500  	// Ensure any referenced declarations are written out too.
   501  	w.p.pushDecl(obj)
   502  	w.string(name)
   503  	w.pkg(obj.Pkg())
   504  }
   505  
   506  func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
   507  	w.data.uint64(w.p.typOff(t, pkg))
   508  }
   509  
   510  func (p *iexporter) newWriter() *exportWriter {
   511  	return &exportWriter{p: p}
   512  }
   513  
   514  func (w *exportWriter) flush() uint64 {
   515  	off := uint64(w.p.data0.Len())
   516  	io.Copy(&w.p.data0, &w.data)
   517  	return off
   518  }
   519  
   520  func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
   521  	off, ok := p.typIndex[t]
   522  	if !ok {
   523  		w := p.newWriter()
   524  		w.doTyp(t, pkg)
   525  		off = predeclReserved + w.flush()
   526  		p.typIndex[t] = off
   527  	}
   528  	return off
   529  }
   530  
   531  func (w *exportWriter) startType(k itag) {
   532  	w.data.uint64(uint64(k))
   533  }
   534  
   535  func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
   536  	if trace {
   537  		w.p.trace("exporting type %s (%T)", t, t)
   538  		w.p.indent++
   539  		defer func() {
   540  			w.p.indent--
   541  			w.p.trace("=> %s", t)
   542  		}()
   543  	}
   544  	switch t := t.(type) {
   545  	case *types.Named:
   546  		if targs := typeparams.NamedTypeArgs(t); targs.Len() > 0 {
   547  			w.startType(instanceType)
   548  			// TODO(rfindley): investigate if this position is correct, and if it
   549  			// matters.
   550  			w.pos(t.Obj().Pos())
   551  			w.typeList(targs, pkg)
   552  			w.typ(typeparams.NamedTypeOrigin(t), pkg)
   553  			return
   554  		}
   555  		w.startType(definedType)
   556  		w.qualifiedIdent(t.Obj())
   557  
   558  	case *typeparams.TypeParam:
   559  		w.startType(typeParamType)
   560  		w.qualifiedIdent(t.Obj())
   561  
   562  	case *types.Pointer:
   563  		w.startType(pointerType)
   564  		w.typ(t.Elem(), pkg)
   565  
   566  	case *types.Slice:
   567  		w.startType(sliceType)
   568  		w.typ(t.Elem(), pkg)
   569  
   570  	case *types.Array:
   571  		w.startType(arrayType)
   572  		w.uint64(uint64(t.Len()))
   573  		w.typ(t.Elem(), pkg)
   574  
   575  	case *types.Chan:
   576  		w.startType(chanType)
   577  		// 1 RecvOnly; 2 SendOnly; 3 SendRecv
   578  		var dir uint64
   579  		switch t.Dir() {
   580  		case types.RecvOnly:
   581  			dir = 1
   582  		case types.SendOnly:
   583  			dir = 2
   584  		case types.SendRecv:
   585  			dir = 3
   586  		}
   587  		w.uint64(dir)
   588  		w.typ(t.Elem(), pkg)
   589  
   590  	case *types.Map:
   591  		w.startType(mapType)
   592  		w.typ(t.Key(), pkg)
   593  		w.typ(t.Elem(), pkg)
   594  
   595  	case *types.Signature:
   596  		w.startType(signatureType)
   597  		w.setPkg(pkg, true)
   598  		w.signature(t)
   599  
   600  	case *types.Struct:
   601  		w.startType(structType)
   602  		w.setPkg(pkg, true)
   603  
   604  		n := t.NumFields()
   605  		w.uint64(uint64(n))
   606  		for i := 0; i < n; i++ {
   607  			f := t.Field(i)
   608  			w.pos(f.Pos())
   609  			w.string(f.Name())
   610  			w.typ(f.Type(), pkg)
   611  			w.bool(f.Anonymous())
   612  			w.string(t.Tag(i)) // note (or tag)
   613  		}
   614  
   615  	case *types.Interface:
   616  		w.startType(interfaceType)
   617  		w.setPkg(pkg, true)
   618  
   619  		n := t.NumEmbeddeds()
   620  		w.uint64(uint64(n))
   621  		for i := 0; i < n; i++ {
   622  			ft := t.EmbeddedType(i)
   623  			tPkg := pkg
   624  			if named, _ := ft.(*types.Named); named != nil {
   625  				w.pos(named.Obj().Pos())
   626  			} else {
   627  				w.pos(token.NoPos)
   628  			}
   629  			w.typ(ft, tPkg)
   630  		}
   631  
   632  		n = t.NumExplicitMethods()
   633  		w.uint64(uint64(n))
   634  		for i := 0; i < n; i++ {
   635  			m := t.ExplicitMethod(i)
   636  			w.pos(m.Pos())
   637  			w.string(m.Name())
   638  			sig, _ := m.Type().(*types.Signature)
   639  			w.signature(sig)
   640  		}
   641  
   642  	case *typeparams.Union:
   643  		w.startType(unionType)
   644  		nt := t.Len()
   645  		w.uint64(uint64(nt))
   646  		for i := 0; i < nt; i++ {
   647  			term := t.Term(i)
   648  			w.bool(term.Tilde())
   649  			w.typ(term.Type(), pkg)
   650  		}
   651  
   652  	default:
   653  		panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
   654  	}
   655  }
   656  
   657  func (w *exportWriter) setPkg(pkg *types.Package, write bool) {
   658  	if write {
   659  		w.pkg(pkg)
   660  	}
   661  
   662  	w.currPkg = pkg
   663  }
   664  
   665  func (w *exportWriter) signature(sig *types.Signature) {
   666  	w.paramList(sig.Params())
   667  	w.paramList(sig.Results())
   668  	if sig.Params().Len() > 0 {
   669  		w.bool(sig.Variadic())
   670  	}
   671  }
   672  
   673  func (w *exportWriter) typeList(ts *typeparams.TypeList, pkg *types.Package) {
   674  	w.uint64(uint64(ts.Len()))
   675  	for i := 0; i < ts.Len(); i++ {
   676  		w.typ(ts.At(i), pkg)
   677  	}
   678  }
   679  
   680  func (w *exportWriter) tparamList(prefix string, list *typeparams.TypeParamList, pkg *types.Package) {
   681  	ll := uint64(list.Len())
   682  	w.uint64(ll)
   683  	for i := 0; i < list.Len(); i++ {
   684  		tparam := list.At(i)
   685  		// Set the type parameter exportName before exporting its type.
   686  		exportName := tparamExportName(prefix, tparam)
   687  		w.p.tparamNames[tparam.Obj()] = exportName
   688  		w.typ(list.At(i), pkg)
   689  	}
   690  }
   691  
   692  const blankMarker = "$"
   693  
   694  // tparamExportName returns the 'exported' name of a type parameter, which
   695  // differs from its actual object name: it is prefixed with a qualifier, and
   696  // blank type parameter names are disambiguated by their index in the type
   697  // parameter list.
   698  func tparamExportName(prefix string, tparam *typeparams.TypeParam) string {
   699  	assert(prefix != "")
   700  	name := tparam.Obj().Name()
   701  	if name == "_" {
   702  		name = blankMarker + strconv.Itoa(tparam.Index())
   703  	}
   704  	return prefix + "." + name
   705  }
   706  
   707  // tparamName returns the real name of a type parameter, after stripping its
   708  // qualifying prefix and reverting blank-name encoding. See tparamExportName
   709  // for details.
   710  func tparamName(exportName string) string {
   711  	// Remove the "path" from the type param name that makes it unique.
   712  	ix := strings.LastIndex(exportName, ".")
   713  	if ix < 0 {
   714  		errorf("malformed type parameter export name %s: missing prefix", exportName)
   715  	}
   716  	name := exportName[ix+1:]
   717  	if strings.HasPrefix(name, blankMarker) {
   718  		return "_"
   719  	}
   720  	return name
   721  }
   722  
   723  func (w *exportWriter) paramList(tup *types.Tuple) {
   724  	n := tup.Len()
   725  	w.uint64(uint64(n))
   726  	for i := 0; i < n; i++ {
   727  		w.param(tup.At(i))
   728  	}
   729  }
   730  
   731  func (w *exportWriter) param(obj types.Object) {
   732  	w.pos(obj.Pos())
   733  	w.localIdent(obj)
   734  	w.typ(obj.Type(), obj.Pkg())
   735  }
   736  
   737  func (w *exportWriter) value(typ types.Type, v constant.Value) {
   738  	w.typ(typ, nil)
   739  	if w.p.version >= iexportVersionGo1_18 {
   740  		w.int64(int64(v.Kind()))
   741  	}
   742  
   743  	switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
   744  	case types.IsBoolean:
   745  		w.bool(constant.BoolVal(v))
   746  	case types.IsInteger:
   747  		var i big.Int
   748  		if i64, exact := constant.Int64Val(v); exact {
   749  			i.SetInt64(i64)
   750  		} else if ui64, exact := constant.Uint64Val(v); exact {
   751  			i.SetUint64(ui64)
   752  		} else {
   753  			i.SetString(v.ExactString(), 10)
   754  		}
   755  		w.mpint(&i, typ)
   756  	case types.IsFloat:
   757  		f := constantToFloat(v)
   758  		w.mpfloat(f, typ)
   759  	case types.IsComplex:
   760  		w.mpfloat(constantToFloat(constant.Real(v)), typ)
   761  		w.mpfloat(constantToFloat(constant.Imag(v)), typ)
   762  	case types.IsString:
   763  		w.string(constant.StringVal(v))
   764  	default:
   765  		if b.Kind() == types.Invalid {
   766  			// package contains type errors
   767  			break
   768  		}
   769  		panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying()))
   770  	}
   771  }
   772  
   773  // constantToFloat converts a constant.Value with kind constant.Float to a
   774  // big.Float.
   775  func constantToFloat(x constant.Value) *big.Float {
   776  	x = constant.ToFloat(x)
   777  	// Use the same floating-point precision (512) as cmd/compile
   778  	// (see Mpprec in cmd/compile/internal/gc/mpfloat.go).
   779  	const mpprec = 512
   780  	var f big.Float
   781  	f.SetPrec(mpprec)
   782  	if v, exact := constant.Float64Val(x); exact {
   783  		// float64
   784  		f.SetFloat64(v)
   785  	} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
   786  		// TODO(gri): add big.Rat accessor to constant.Value.
   787  		n := valueToRat(num)
   788  		d := valueToRat(denom)
   789  		f.SetRat(n.Quo(n, d))
   790  	} else {
   791  		// Value too large to represent as a fraction => inaccessible.
   792  		// TODO(gri): add big.Float accessor to constant.Value.
   793  		_, ok := f.SetString(x.ExactString())
   794  		assert(ok)
   795  	}
   796  	return &f
   797  }
   798  
   799  // mpint exports a multi-precision integer.
   800  //
   801  // For unsigned types, small values are written out as a single
   802  // byte. Larger values are written out as a length-prefixed big-endian
   803  // byte string, where the length prefix is encoded as its complement.
   804  // For example, bytes 0, 1, and 2 directly represent the integer
   805  // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
   806  // 2-, and 3-byte big-endian string follow.
   807  //
   808  // Encoding for signed types use the same general approach as for
   809  // unsigned types, except small values use zig-zag encoding and the
   810  // bottom bit of length prefix byte for large values is reserved as a
   811  // sign bit.
   812  //
   813  // The exact boundary between small and large encodings varies
   814  // according to the maximum number of bytes needed to encode a value
   815  // of type typ. As a special case, 8-bit types are always encoded as a
   816  // single byte.
   817  //
   818  // TODO(mdempsky): Is this level of complexity really worthwhile?
   819  func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
   820  	basic, ok := typ.Underlying().(*types.Basic)
   821  	if !ok {
   822  		panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
   823  	}
   824  
   825  	signed, maxBytes := intSize(basic)
   826  
   827  	negative := x.Sign() < 0
   828  	if !signed && negative {
   829  		panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
   830  	}
   831  
   832  	b := x.Bytes()
   833  	if len(b) > 0 && b[0] == 0 {
   834  		panic(internalErrorf("leading zeros"))
   835  	}
   836  	if uint(len(b)) > maxBytes {
   837  		panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
   838  	}
   839  
   840  	maxSmall := 256 - maxBytes
   841  	if signed {
   842  		maxSmall = 256 - 2*maxBytes
   843  	}
   844  	if maxBytes == 1 {
   845  		maxSmall = 256
   846  	}
   847  
   848  	// Check if x can use small value encoding.
   849  	if len(b) <= 1 {
   850  		var ux uint
   851  		if len(b) == 1 {
   852  			ux = uint(b[0])
   853  		}
   854  		if signed {
   855  			ux <<= 1
   856  			if negative {
   857  				ux--
   858  			}
   859  		}
   860  		if ux < maxSmall {
   861  			w.data.WriteByte(byte(ux))
   862  			return
   863  		}
   864  	}
   865  
   866  	n := 256 - uint(len(b))
   867  	if signed {
   868  		n = 256 - 2*uint(len(b))
   869  		if negative {
   870  			n |= 1
   871  		}
   872  	}
   873  	if n < maxSmall || n >= 256 {
   874  		panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
   875  	}
   876  
   877  	w.data.WriteByte(byte(n))
   878  	w.data.Write(b)
   879  }
   880  
   881  // mpfloat exports a multi-precision floating point number.
   882  //
   883  // The number's value is decomposed into mantissa × 2**exponent, where
   884  // mantissa is an integer. The value is written out as mantissa (as a
   885  // multi-precision integer) and then the exponent, except exponent is
   886  // omitted if mantissa is zero.
   887  func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
   888  	if f.IsInf() {
   889  		panic("infinite constant")
   890  	}
   891  
   892  	// Break into f = mant × 2**exp, with 0.5 <= mant < 1.
   893  	var mant big.Float
   894  	exp := int64(f.MantExp(&mant))
   895  
   896  	// Scale so that mant is an integer.
   897  	prec := mant.MinPrec()
   898  	mant.SetMantExp(&mant, int(prec))
   899  	exp -= int64(prec)
   900  
   901  	manti, acc := mant.Int(nil)
   902  	if acc != big.Exact {
   903  		panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
   904  	}
   905  	w.mpint(manti, typ)
   906  	if manti.Sign() != 0 {
   907  		w.int64(exp)
   908  	}
   909  }
   910  
   911  func (w *exportWriter) bool(b bool) bool {
   912  	var x uint64
   913  	if b {
   914  		x = 1
   915  	}
   916  	w.uint64(x)
   917  	return b
   918  }
   919  
   920  func (w *exportWriter) int64(x int64)   { w.data.int64(x) }
   921  func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
   922  func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
   923  
   924  func (w *exportWriter) localIdent(obj types.Object) {
   925  	// Anonymous parameters.
   926  	if obj == nil {
   927  		w.string("")
   928  		return
   929  	}
   930  
   931  	name := obj.Name()
   932  	if name == "_" {
   933  		w.string("_")
   934  		return
   935  	}
   936  
   937  	w.string(name)
   938  }
   939  
   940  type intWriter struct {
   941  	bytes.Buffer
   942  }
   943  
   944  func (w *intWriter) int64(x int64) {
   945  	var buf [binary.MaxVarintLen64]byte
   946  	n := binary.PutVarint(buf[:], x)
   947  	w.Write(buf[:n])
   948  }
   949  
   950  func (w *intWriter) uint64(x uint64) {
   951  	var buf [binary.MaxVarintLen64]byte
   952  	n := binary.PutUvarint(buf[:], x)
   953  	w.Write(buf[:n])
   954  }
   955  
   956  func assert(cond bool) {
   957  	if !cond {
   958  		panic("internal error: assertion failed")
   959  	}
   960  }
   961  
   962  // The below is copied from go/src/cmd/compile/internal/gc/syntax.go.
   963  
   964  // objQueue is a FIFO queue of types.Object. The zero value of objQueue is
   965  // a ready-to-use empty queue.
   966  type objQueue struct {
   967  	ring       []types.Object
   968  	head, tail int
   969  }
   970  
   971  // empty returns true if q contains no Nodes.
   972  func (q *objQueue) empty() bool {
   973  	return q.head == q.tail
   974  }
   975  
   976  // pushTail appends n to the tail of the queue.
   977  func (q *objQueue) pushTail(obj types.Object) {
   978  	if len(q.ring) == 0 {
   979  		q.ring = make([]types.Object, 16)
   980  	} else if q.head+len(q.ring) == q.tail {
   981  		// Grow the ring.
   982  		nring := make([]types.Object, len(q.ring)*2)
   983  		// Copy the old elements.
   984  		part := q.ring[q.head%len(q.ring):]
   985  		if q.tail-q.head <= len(part) {
   986  			part = part[:q.tail-q.head]
   987  			copy(nring, part)
   988  		} else {
   989  			pos := copy(nring, part)
   990  			copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
   991  		}
   992  		q.ring, q.head, q.tail = nring, 0, q.tail-q.head
   993  	}
   994  
   995  	q.ring[q.tail%len(q.ring)] = obj
   996  	q.tail++
   997  }
   998  
   999  // popHead pops a node from the head of the queue. It panics if q is empty.
  1000  func (q *objQueue) popHead() types.Object {
  1001  	if q.empty() {
  1002  		panic("dequeue empty")
  1003  	}
  1004  	obj := q.ring[q.head%len(q.ring)]
  1005  	q.head++
  1006  	return obj
  1007  }