mirror of
https://github.com/golang/go
synced 2024-11-22 03:44:39 -07:00
cmd/compile/internal/importer: drop support for indexed format
Drop support for the indexed format from the test-only Import function. Adds several TODOs for further tech debt reduction. Change-Id: I45cc5ffce43082a145ccb918face067cdccc5ecd Reviewed-on: https://go-review.googlesource.com/c/go/+/626695 Commit-Queue: Tim King <taking@google.com> Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
64e7f66b26
commit
b0bbfb1e0f
@ -15,6 +15,8 @@ import (
|
||||
)
|
||||
|
||||
func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
// TODO(taking): replace with src/cmd/internal/archive.ReadHeader.
|
||||
|
||||
// See $GOROOT/include/ar.h.
|
||||
hdr := make([]byte, 16+12+6+6+8+10+2)
|
||||
_, err = io.ReadFull(r, hdr)
|
||||
@ -43,7 +45,12 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
||||
//
|
||||
// If size is non-negative, it's the number of bytes of export data
|
||||
// still available to read from r.
|
||||
//
|
||||
// This function should only be used in tests.
|
||||
func FindExportData(r *bufio.Reader) (hdr string, size int, err error) {
|
||||
// TODO(taking): Move into a src/internal package then
|
||||
// dedup with cmd/compile/internal/noder.findExportData and go/internal/gcimporter.FindExportData.
|
||||
|
||||
// Read first line to make sure this is an object file.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
@ -71,6 +78,7 @@ func FindExportData(r *bufio.Reader) (hdr string, size int, err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO(taking): The else case is likely dead. Otherwise, size<0. Return an error instead.
|
||||
|
||||
// Now at __.PKGDEF in archive or still at beginning of file.
|
||||
// Either way, line should begin with "go object ".
|
||||
|
@ -2,7 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// package importer implements Import for gc-generated object files.
|
||||
// This file contains the FindPkg and Import functions for tests
|
||||
// to use gc-generated object files.
|
||||
|
||||
package importer
|
||||
|
||||
import (
|
||||
@ -75,7 +77,11 @@ var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have n
|
||||
// path based on package information provided by build.Import (using
|
||||
// the build.Default build.Context). A relative srcDir is interpreted
|
||||
// relative to the current working directory.
|
||||
//
|
||||
// This function should only be used in tests.
|
||||
func FindPkg(path, srcDir string) (filename, id string, err error) {
|
||||
// TODO(taking): move FindPkg into src/internal and dedup src/go/internal/gcimporter.FindPkg
|
||||
|
||||
if path == "" {
|
||||
return "", "", errors.New("path is empty")
|
||||
}
|
||||
@ -147,6 +153,8 @@ notfound:
|
||||
// Import imports a gc-generated package given its import path and srcDir, adds
|
||||
// the corresponding package object to the packages map, and returns the object.
|
||||
// The packages map must contain all packages already imported.
|
||||
//
|
||||
// This function should only be used in tests.
|
||||
func Import(packages map[string]*types2.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types2.Package, err error) {
|
||||
var rc io.ReadCloser
|
||||
var id string
|
||||
@ -208,6 +216,7 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
||||
err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
|
||||
|
||||
case "$$B\n":
|
||||
// TODO(taking): minimize code delta with src/go/internal/gcimporter.Import.
|
||||
var data []byte
|
||||
var r io.Reader = buf
|
||||
if size >= 0 {
|
||||
@ -225,18 +234,18 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
||||
exportFormat := data[0]
|
||||
s := string(data[1:])
|
||||
|
||||
// The indexed export format starts with an 'i'; the older
|
||||
// binary export format starts with a 'c', 'd', or 'v'
|
||||
// (from "version"). Select appropriate importer.
|
||||
// The unified export format starts with a 'u'; the indexed export
|
||||
// format starts with an 'i'; and the older binary export format
|
||||
// starts with a 'c', 'd', or 'v' (from "version"). Select
|
||||
// appropriate importer.
|
||||
switch exportFormat {
|
||||
case 'u':
|
||||
// TODO(taking): Look into whether this should be LastIndex instead of Index.
|
||||
s = s[:strings.Index(s, "\n$$\n")]
|
||||
input := pkgbits.NewPkgDecoder(id, s)
|
||||
pkg = ReadPackage(nil, packages, input)
|
||||
case 'i':
|
||||
pkg, err = ImportData(packages, s, id)
|
||||
default:
|
||||
err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
|
||||
err = fmt.Errorf("import %q: binary export format %q is no longer supported (recompile package)", path, exportFormat)
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -1,803 +0,0 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Indexed package import.
|
||||
// See cmd/compile/internal/typecheck/iexport.go for the export data format.
|
||||
|
||||
package importer
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types2"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"io"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type intReader struct {
|
||||
*strings.Reader
|
||||
path string
|
||||
}
|
||||
|
||||
func (r *intReader) int64() int64 {
|
||||
i, err := binary.ReadVarint(r.Reader)
|
||||
if err != nil {
|
||||
errorf("import %q: read varint error: %v", r.path, err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (r *intReader) uint64() uint64 {
|
||||
i, err := binary.ReadUvarint(r.Reader)
|
||||
if err != nil {
|
||||
errorf("import %q: read varint error: %v", r.path, err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Keep this in sync with constants in iexport.go.
|
||||
const (
|
||||
iexportVersionGo1_11 = 0
|
||||
iexportVersionPosCol = 1
|
||||
iexportVersionGenerics = 2
|
||||
iexportVersionGo1_18 = 2
|
||||
|
||||
iexportVersionCurrent = 2
|
||||
)
|
||||
|
||||
type ident struct {
|
||||
pkg *types2.Package
|
||||
name string
|
||||
}
|
||||
|
||||
const predeclReserved = 32
|
||||
|
||||
type itag uint64
|
||||
|
||||
const (
|
||||
// Types
|
||||
definedType itag = iota
|
||||
pointerType
|
||||
sliceType
|
||||
arrayType
|
||||
chanType
|
||||
mapType
|
||||
signatureType
|
||||
structType
|
||||
interfaceType
|
||||
typeParamType
|
||||
instanceType
|
||||
unionType
|
||||
)
|
||||
|
||||
// ImportData imports a package from the serialized package data
|
||||
// and returns the number of bytes consumed and a reference to the package.
|
||||
// If the export data version is not recognized or the format is otherwise
|
||||
// compromised, an error is returned.
|
||||
func ImportData(imports map[string]*types2.Package, data, path string) (pkg *types2.Package, err error) {
|
||||
const currentVersion = iexportVersionCurrent
|
||||
version := int64(-1)
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if version > currentVersion {
|
||||
err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
|
||||
} else {
|
||||
err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
r := &intReader{strings.NewReader(data), path}
|
||||
|
||||
version = int64(r.uint64())
|
||||
switch version {
|
||||
case iexportVersionGo1_18, iexportVersionPosCol, iexportVersionGo1_11:
|
||||
default:
|
||||
errorf("unknown iexport format version %d", version)
|
||||
}
|
||||
|
||||
sLen := int64(r.uint64())
|
||||
dLen := int64(r.uint64())
|
||||
|
||||
whence, _ := r.Seek(0, io.SeekCurrent)
|
||||
stringData := data[whence : whence+sLen]
|
||||
declData := data[whence+sLen : whence+sLen+dLen]
|
||||
r.Seek(sLen+dLen, io.SeekCurrent)
|
||||
|
||||
p := iimporter{
|
||||
exportVersion: version,
|
||||
ipath: path,
|
||||
version: int(version),
|
||||
|
||||
stringData: stringData,
|
||||
pkgCache: make(map[uint64]*types2.Package),
|
||||
posBaseCache: make(map[uint64]*syntax.PosBase),
|
||||
|
||||
declData: declData,
|
||||
pkgIndex: make(map[*types2.Package]map[string]uint64),
|
||||
typCache: make(map[uint64]types2.Type),
|
||||
// Separate map for typeparams, keyed by their package and unique
|
||||
// name (name with subscript).
|
||||
tparamIndex: make(map[ident]*types2.TypeParam),
|
||||
}
|
||||
|
||||
for i, pt := range predeclared {
|
||||
p.typCache[uint64(i)] = pt
|
||||
}
|
||||
// Special handling for "any", whose representation may be changed by the
|
||||
// gotypesalias GODEBUG variable.
|
||||
p.typCache[uint64(len(predeclared))] = types2.Universe.Lookup("any").Type()
|
||||
|
||||
pkgList := make([]*types2.Package, r.uint64())
|
||||
for i := range pkgList {
|
||||
pkgPathOff := r.uint64()
|
||||
pkgPath := p.stringAt(pkgPathOff)
|
||||
pkgName := p.stringAt(r.uint64())
|
||||
_ = int(r.uint64()) // was package height, but not necessary anymore.
|
||||
|
||||
if pkgPath == "" {
|
||||
pkgPath = path
|
||||
}
|
||||
pkg := imports[pkgPath]
|
||||
if pkg == nil {
|
||||
pkg = types2.NewPackage(pkgPath, pkgName)
|
||||
imports[pkgPath] = pkg
|
||||
} else {
|
||||
if pkg.Name() != pkgName {
|
||||
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
|
||||
}
|
||||
}
|
||||
|
||||
p.pkgCache[pkgPathOff] = pkg
|
||||
|
||||
nameIndex := make(map[string]uint64)
|
||||
for nSyms := r.uint64(); nSyms > 0; nSyms-- {
|
||||
name := p.stringAt(r.uint64())
|
||||
nameIndex[name] = r.uint64()
|
||||
}
|
||||
|
||||
p.pkgIndex[pkg] = nameIndex
|
||||
pkgList[i] = pkg
|
||||
}
|
||||
|
||||
localpkg := pkgList[0]
|
||||
|
||||
names := make([]string, 0, len(p.pkgIndex[localpkg]))
|
||||
for name := range p.pkgIndex[localpkg] {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, name := range names {
|
||||
p.doDecl(localpkg, name)
|
||||
}
|
||||
|
||||
// SetConstraint can't be called if the constraint type is not yet complete.
|
||||
// When type params are created in the 'P' case of (*importReader).obj(),
|
||||
// the associated constraint type may not be complete due to recursion.
|
||||
// Therefore, we defer calling SetConstraint there, and call it here instead
|
||||
// after all types are complete.
|
||||
for _, d := range p.later {
|
||||
d.t.SetConstraint(d.constraint)
|
||||
}
|
||||
// record all referenced packages as imports
|
||||
list := append(([]*types2.Package)(nil), pkgList[1:]...)
|
||||
slices.SortFunc(list, func(a, b *types2.Package) int {
|
||||
return strings.Compare(a.Path(), b.Path())
|
||||
})
|
||||
localpkg.SetImports(list)
|
||||
|
||||
// package was imported completely and without errors
|
||||
localpkg.MarkComplete()
|
||||
|
||||
return localpkg, nil
|
||||
}
|
||||
|
||||
type setConstraintArgs struct {
|
||||
t *types2.TypeParam
|
||||
constraint types2.Type
|
||||
}
|
||||
|
||||
type iimporter struct {
|
||||
exportVersion int64
|
||||
ipath string
|
||||
version int
|
||||
|
||||
stringData string
|
||||
pkgCache map[uint64]*types2.Package
|
||||
posBaseCache map[uint64]*syntax.PosBase
|
||||
|
||||
declData string
|
||||
pkgIndex map[*types2.Package]map[string]uint64
|
||||
typCache map[uint64]types2.Type
|
||||
tparamIndex map[ident]*types2.TypeParam
|
||||
|
||||
interfaceList []*types2.Interface
|
||||
|
||||
// Arguments for calls to SetConstraint that are deferred due to recursive types
|
||||
later []setConstraintArgs
|
||||
}
|
||||
|
||||
func (p *iimporter) doDecl(pkg *types2.Package, name string) {
|
||||
// See if we've already imported this declaration.
|
||||
if obj := pkg.Scope().Lookup(name); obj != nil {
|
||||
return
|
||||
}
|
||||
|
||||
off, ok := p.pkgIndex[pkg][name]
|
||||
if !ok {
|
||||
errorf("%v.%v not in index", pkg, name)
|
||||
}
|
||||
|
||||
r := &importReader{p: p, currPkg: pkg}
|
||||
r.declReader.Reset(p.declData[off:])
|
||||
|
||||
r.obj(name)
|
||||
}
|
||||
|
||||
func (p *iimporter) stringAt(off uint64) string {
|
||||
var x [binary.MaxVarintLen64]byte
|
||||
n := copy(x[:], p.stringData[off:])
|
||||
|
||||
slen, n := binary.Uvarint(x[:n])
|
||||
if n <= 0 {
|
||||
errorf("varint failed")
|
||||
}
|
||||
spos := off + uint64(n)
|
||||
return p.stringData[spos : spos+slen]
|
||||
}
|
||||
|
||||
func (p *iimporter) pkgAt(off uint64) *types2.Package {
|
||||
if pkg, ok := p.pkgCache[off]; ok {
|
||||
return pkg
|
||||
}
|
||||
path := p.stringAt(off)
|
||||
errorf("missing package %q in %q", path, p.ipath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *iimporter) posBaseAt(off uint64) *syntax.PosBase {
|
||||
if posBase, ok := p.posBaseCache[off]; ok {
|
||||
return posBase
|
||||
}
|
||||
filename := p.stringAt(off)
|
||||
posBase := syntax.NewTrimmedFileBase(filename, true)
|
||||
p.posBaseCache[off] = posBase
|
||||
return posBase
|
||||
}
|
||||
|
||||
func (p *iimporter) typAt(off uint64, base *types2.Named) types2.Type {
|
||||
if t, ok := p.typCache[off]; ok && canReuse(base, t) {
|
||||
return t
|
||||
}
|
||||
|
||||
if off < predeclReserved {
|
||||
errorf("predeclared type missing from cache: %v", off)
|
||||
}
|
||||
|
||||
r := &importReader{p: p}
|
||||
r.declReader.Reset(p.declData[off-predeclReserved:])
|
||||
t := r.doType(base)
|
||||
|
||||
if canReuse(base, t) {
|
||||
p.typCache[off] = t
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// canReuse reports whether the type rhs on the RHS of the declaration for def
|
||||
// may be re-used.
|
||||
//
|
||||
// Specifically, if def is non-nil and rhs is an interface type with methods, it
|
||||
// may not be re-used because we have a convention of setting the receiver type
|
||||
// for interface methods to def.
|
||||
func canReuse(def *types2.Named, rhs types2.Type) bool {
|
||||
if def == nil {
|
||||
return true
|
||||
}
|
||||
iface, _ := rhs.(*types2.Interface)
|
||||
if iface == nil {
|
||||
return true
|
||||
}
|
||||
// Don't use iface.Empty() here as iface may not be complete.
|
||||
return iface.NumEmbeddeds() == 0 && iface.NumExplicitMethods() == 0
|
||||
}
|
||||
|
||||
type importReader struct {
|
||||
p *iimporter
|
||||
declReader strings.Reader
|
||||
currPkg *types2.Package
|
||||
prevPosBase *syntax.PosBase
|
||||
prevLine int64
|
||||
prevColumn int64
|
||||
}
|
||||
|
||||
func (r *importReader) obj(name string) {
|
||||
tag := r.byte()
|
||||
pos := r.pos()
|
||||
|
||||
switch tag {
|
||||
case 'A', 'B':
|
||||
var tparams []*types2.TypeParam
|
||||
if tag == 'B' {
|
||||
tparams = r.tparamList()
|
||||
}
|
||||
rhs := r.typ()
|
||||
const enabled = true // This is now always enabled within the compiler.
|
||||
r.declare(newAliasTypeName(enabled, pos, r.currPkg, name, rhs, tparams))
|
||||
|
||||
case 'C':
|
||||
typ, val := r.value()
|
||||
|
||||
r.declare(types2.NewConst(pos, r.currPkg, name, typ, val))
|
||||
|
||||
case 'F', 'G':
|
||||
var tparams []*types2.TypeParam
|
||||
if tag == 'G' {
|
||||
tparams = r.tparamList()
|
||||
}
|
||||
sig := r.signature(nil, nil, tparams)
|
||||
r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
|
||||
|
||||
case 'T', 'U':
|
||||
// Types can be recursive. We need to setup a stub
|
||||
// declaration before recursing.
|
||||
obj := types2.NewTypeName(pos, r.currPkg, name, nil)
|
||||
named := types2.NewNamed(obj, nil, nil)
|
||||
// Declare obj before calling r.tparamList, so the new type name is recognized
|
||||
// if used in the constraint of one of its own typeparams (see #48280).
|
||||
r.declare(obj)
|
||||
if tag == 'U' {
|
||||
tparams := r.tparamList()
|
||||
named.SetTypeParams(tparams)
|
||||
}
|
||||
|
||||
underlying := r.p.typAt(r.uint64(), named).Underlying()
|
||||
named.SetUnderlying(underlying)
|
||||
|
||||
if !isInterface(underlying) {
|
||||
for n := r.uint64(); n > 0; n-- {
|
||||
mpos := r.pos()
|
||||
mname := r.ident()
|
||||
recv := r.param()
|
||||
|
||||
// If the receiver has any targs, set those as the
|
||||
// rparams of the method (since those are the
|
||||
// typeparams being used in the method sig/body).
|
||||
targs := baseType(recv.Type()).TypeArgs()
|
||||
var rparams []*types2.TypeParam
|
||||
if targs.Len() > 0 {
|
||||
rparams = make([]*types2.TypeParam, targs.Len())
|
||||
for i := range rparams {
|
||||
rparams[i], _ = targs.At(i).(*types2.TypeParam)
|
||||
}
|
||||
}
|
||||
msig := r.signature(recv, rparams, nil)
|
||||
|
||||
named.AddMethod(types2.NewFunc(mpos, r.currPkg, mname, msig))
|
||||
}
|
||||
}
|
||||
|
||||
case 'P':
|
||||
// We need to "declare" a typeparam in order to have a name that
|
||||
// can be referenced recursively (if needed) in the type param's
|
||||
// bound.
|
||||
if r.p.exportVersion < iexportVersionGenerics {
|
||||
errorf("unexpected type param type")
|
||||
}
|
||||
name0 := typecheck.TparamName(name)
|
||||
if name0 == "" {
|
||||
errorf("malformed type parameter export name %s: missing prefix", name)
|
||||
}
|
||||
|
||||
tn := types2.NewTypeName(pos, r.currPkg, name0, nil)
|
||||
t := types2.NewTypeParam(tn, nil)
|
||||
// To handle recursive references to the typeparam within its
|
||||
// bound, save the partial type in tparamIndex before reading the bounds.
|
||||
id := ident{r.currPkg, name}
|
||||
r.p.tparamIndex[id] = t
|
||||
|
||||
var implicit bool
|
||||
if r.p.exportVersion >= iexportVersionGo1_18 {
|
||||
implicit = r.bool()
|
||||
}
|
||||
constraint := r.typ()
|
||||
if implicit {
|
||||
iface, _ := constraint.(*types2.Interface)
|
||||
if iface == nil {
|
||||
errorf("non-interface constraint marked implicit")
|
||||
}
|
||||
iface.MarkImplicit()
|
||||
}
|
||||
// The constraint type may not be complete, if we
|
||||
// are in the middle of a type recursion involving type
|
||||
// constraints. So, we defer SetConstraint until we have
|
||||
// completely set up all types in ImportData.
|
||||
r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
|
||||
|
||||
case 'V':
|
||||
typ := r.typ()
|
||||
|
||||
r.declare(types2.NewVar(pos, r.currPkg, name, typ))
|
||||
|
||||
default:
|
||||
errorf("unexpected tag: %v", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) declare(obj types2.Object) {
|
||||
obj.Pkg().Scope().Insert(obj)
|
||||
}
|
||||
|
||||
func (r *importReader) value() (typ types2.Type, val constant.Value) {
|
||||
typ = r.typ()
|
||||
if r.p.exportVersion >= iexportVersionGo1_18 {
|
||||
// TODO: add support for using the kind
|
||||
_ = constant.Kind(r.int64())
|
||||
}
|
||||
|
||||
switch b := typ.Underlying().(*types2.Basic); b.Info() & types2.IsConstType {
|
||||
case types2.IsBoolean:
|
||||
val = constant.MakeBool(r.bool())
|
||||
|
||||
case types2.IsString:
|
||||
val = constant.MakeString(r.string())
|
||||
|
||||
case types2.IsInteger:
|
||||
var x big.Int
|
||||
r.mpint(&x, b)
|
||||
val = constant.Make(&x)
|
||||
|
||||
case types2.IsFloat:
|
||||
val = r.mpfloat(b)
|
||||
|
||||
case types2.IsComplex:
|
||||
re := r.mpfloat(b)
|
||||
im := r.mpfloat(b)
|
||||
val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
|
||||
|
||||
default:
|
||||
errorf("unexpected type %v", typ) // panics
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func intSize(b *types2.Basic) (signed bool, maxBytes uint) {
|
||||
if (b.Info() & types2.IsUntyped) != 0 {
|
||||
return true, 64
|
||||
}
|
||||
|
||||
switch b.Kind() {
|
||||
case types2.Float32, types2.Complex64:
|
||||
return true, 3
|
||||
case types2.Float64, types2.Complex128:
|
||||
return true, 7
|
||||
}
|
||||
|
||||
signed = (b.Info() & types2.IsUnsigned) == 0
|
||||
switch b.Kind() {
|
||||
case types2.Int8, types2.Uint8:
|
||||
maxBytes = 1
|
||||
case types2.Int16, types2.Uint16:
|
||||
maxBytes = 2
|
||||
case types2.Int32, types2.Uint32:
|
||||
maxBytes = 4
|
||||
default:
|
||||
maxBytes = 8
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *importReader) mpint(x *big.Int, typ *types2.Basic) {
|
||||
signed, maxBytes := intSize(typ)
|
||||
|
||||
maxSmall := 256 - maxBytes
|
||||
if signed {
|
||||
maxSmall = 256 - 2*maxBytes
|
||||
}
|
||||
if maxBytes == 1 {
|
||||
maxSmall = 256
|
||||
}
|
||||
|
||||
n, _ := r.declReader.ReadByte()
|
||||
if uint(n) < maxSmall {
|
||||
v := int64(n)
|
||||
if signed {
|
||||
v >>= 1
|
||||
if n&1 != 0 {
|
||||
v = ^v
|
||||
}
|
||||
}
|
||||
x.SetInt64(v)
|
||||
return
|
||||
}
|
||||
|
||||
v := -n
|
||||
if signed {
|
||||
v = -(n &^ 1) >> 1
|
||||
}
|
||||
if v < 1 || uint(v) > maxBytes {
|
||||
errorf("weird decoding: %v, %v => %v", n, signed, v)
|
||||
}
|
||||
b := make([]byte, v)
|
||||
io.ReadFull(&r.declReader, b)
|
||||
x.SetBytes(b)
|
||||
if signed && n&1 != 0 {
|
||||
x.Neg(x)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) mpfloat(typ *types2.Basic) constant.Value {
|
||||
var mant big.Int
|
||||
r.mpint(&mant, typ)
|
||||
var f big.Float
|
||||
f.SetInt(&mant)
|
||||
if f.Sign() != 0 {
|
||||
f.SetMantExp(&f, int(r.int64()))
|
||||
}
|
||||
return constant.Make(&f)
|
||||
}
|
||||
|
||||
func (r *importReader) ident() string {
|
||||
return r.string()
|
||||
}
|
||||
|
||||
func (r *importReader) qualifiedIdent() (*types2.Package, string) {
|
||||
name := r.string()
|
||||
pkg := r.pkg()
|
||||
return pkg, name
|
||||
}
|
||||
|
||||
func (r *importReader) pos() syntax.Pos {
|
||||
if r.p.version >= 1 {
|
||||
r.posv1()
|
||||
} else {
|
||||
r.posv0()
|
||||
}
|
||||
|
||||
if (r.prevPosBase == nil || r.prevPosBase.Filename() == "") && r.prevLine == 0 && r.prevColumn == 0 {
|
||||
return syntax.Pos{}
|
||||
}
|
||||
|
||||
return syntax.MakePos(r.prevPosBase, uint(r.prevLine), uint(r.prevColumn))
|
||||
}
|
||||
|
||||
func (r *importReader) posv0() {
|
||||
delta := r.int64()
|
||||
if delta != deltaNewFile {
|
||||
r.prevLine += delta
|
||||
} else if l := r.int64(); l == -1 {
|
||||
r.prevLine += deltaNewFile
|
||||
} else {
|
||||
r.prevPosBase = r.posBase()
|
||||
r.prevLine = l
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) posv1() {
|
||||
delta := r.int64()
|
||||
r.prevColumn += delta >> 1
|
||||
if delta&1 != 0 {
|
||||
delta = r.int64()
|
||||
r.prevLine += delta >> 1
|
||||
if delta&1 != 0 {
|
||||
r.prevPosBase = r.posBase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) typ() types2.Type {
|
||||
return r.p.typAt(r.uint64(), nil)
|
||||
}
|
||||
|
||||
func isInterface(t types2.Type) bool {
|
||||
_, ok := t.(*types2.Interface)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (r *importReader) pkg() *types2.Package { return r.p.pkgAt(r.uint64()) }
|
||||
func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
|
||||
func (r *importReader) posBase() *syntax.PosBase { return r.p.posBaseAt(r.uint64()) }
|
||||
|
||||
func (r *importReader) doType(base *types2.Named) types2.Type {
|
||||
switch k := r.kind(); k {
|
||||
default:
|
||||
errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
|
||||
return nil
|
||||
|
||||
case definedType:
|
||||
pkg, name := r.qualifiedIdent()
|
||||
r.p.doDecl(pkg, name)
|
||||
return pkg.Scope().Lookup(name).(*types2.TypeName).Type()
|
||||
case pointerType:
|
||||
return types2.NewPointer(r.typ())
|
||||
case sliceType:
|
||||
return types2.NewSlice(r.typ())
|
||||
case arrayType:
|
||||
n := r.uint64()
|
||||
return types2.NewArray(r.typ(), int64(n))
|
||||
case chanType:
|
||||
dir := chanDir(int(r.uint64()))
|
||||
return types2.NewChan(dir, r.typ())
|
||||
case mapType:
|
||||
return types2.NewMap(r.typ(), r.typ())
|
||||
case signatureType:
|
||||
r.currPkg = r.pkg()
|
||||
return r.signature(nil, nil, nil)
|
||||
|
||||
case structType:
|
||||
r.currPkg = r.pkg()
|
||||
|
||||
fields := make([]*types2.Var, r.uint64())
|
||||
tags := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
fpos := r.pos()
|
||||
fname := r.ident()
|
||||
ftyp := r.typ()
|
||||
emb := r.bool()
|
||||
tag := r.string()
|
||||
|
||||
fields[i] = types2.NewField(fpos, r.currPkg, fname, ftyp, emb)
|
||||
tags[i] = tag
|
||||
}
|
||||
return types2.NewStruct(fields, tags)
|
||||
|
||||
case interfaceType:
|
||||
r.currPkg = r.pkg()
|
||||
|
||||
embeddeds := make([]types2.Type, r.uint64())
|
||||
for i := range embeddeds {
|
||||
_ = r.pos()
|
||||
embeddeds[i] = r.typ()
|
||||
}
|
||||
|
||||
methods := make([]*types2.Func, r.uint64())
|
||||
for i := range methods {
|
||||
mpos := r.pos()
|
||||
mname := r.ident()
|
||||
|
||||
// TODO(mdempsky): Matches bimport.go, but I
|
||||
// don't agree with this.
|
||||
var recv *types2.Var
|
||||
if base != nil {
|
||||
recv = types2.NewVar(syntax.Pos{}, r.currPkg, "", base)
|
||||
}
|
||||
|
||||
msig := r.signature(recv, nil, nil)
|
||||
methods[i] = types2.NewFunc(mpos, r.currPkg, mname, msig)
|
||||
}
|
||||
|
||||
typ := types2.NewInterfaceType(methods, embeddeds)
|
||||
r.p.interfaceList = append(r.p.interfaceList, typ)
|
||||
return typ
|
||||
|
||||
case typeParamType:
|
||||
if r.p.exportVersion < iexportVersionGenerics {
|
||||
errorf("unexpected type param type")
|
||||
}
|
||||
pkg, name := r.qualifiedIdent()
|
||||
id := ident{pkg, name}
|
||||
if t, ok := r.p.tparamIndex[id]; ok {
|
||||
// We're already in the process of importing this typeparam.
|
||||
return t
|
||||
}
|
||||
// Otherwise, import the definition of the typeparam now.
|
||||
r.p.doDecl(pkg, name)
|
||||
return r.p.tparamIndex[id]
|
||||
|
||||
case instanceType:
|
||||
if r.p.exportVersion < iexportVersionGenerics {
|
||||
errorf("unexpected instantiation type")
|
||||
}
|
||||
// pos does not matter for instances: they are positioned on the original
|
||||
// type.
|
||||
_ = r.pos()
|
||||
len := r.uint64()
|
||||
targs := make([]types2.Type, len)
|
||||
for i := range targs {
|
||||
targs[i] = r.typ()
|
||||
}
|
||||
baseType := r.typ()
|
||||
// The imported instantiated type doesn't include any methods, so
|
||||
// we must always use the methods of the base (orig) type.
|
||||
// TODO provide a non-nil *Context
|
||||
t, _ := types2.Instantiate(nil, baseType, targs, false)
|
||||
return t
|
||||
|
||||
case unionType:
|
||||
if r.p.exportVersion < iexportVersionGenerics {
|
||||
errorf("unexpected instantiation type")
|
||||
}
|
||||
terms := make([]*types2.Term, r.uint64())
|
||||
for i := range terms {
|
||||
terms[i] = types2.NewTerm(r.bool(), r.typ())
|
||||
}
|
||||
return types2.NewUnion(terms)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *importReader) kind() itag {
|
||||
return itag(r.uint64())
|
||||
}
|
||||
|
||||
func (r *importReader) signature(recv *types2.Var, rparams, tparams []*types2.TypeParam) *types2.Signature {
|
||||
params := r.paramList()
|
||||
results := r.paramList()
|
||||
variadic := params.Len() > 0 && r.bool()
|
||||
return types2.NewSignatureType(recv, rparams, tparams, params, results, variadic)
|
||||
}
|
||||
|
||||
func (r *importReader) tparamList() []*types2.TypeParam {
|
||||
n := r.uint64()
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
xs := make([]*types2.TypeParam, n)
|
||||
for i := range xs {
|
||||
xs[i] = r.typ().(*types2.TypeParam)
|
||||
}
|
||||
return xs
|
||||
}
|
||||
|
||||
func (r *importReader) paramList() *types2.Tuple {
|
||||
xs := make([]*types2.Var, r.uint64())
|
||||
for i := range xs {
|
||||
xs[i] = r.param()
|
||||
}
|
||||
return types2.NewTuple(xs...)
|
||||
}
|
||||
|
||||
func (r *importReader) param() *types2.Var {
|
||||
pos := r.pos()
|
||||
name := r.ident()
|
||||
typ := r.typ()
|
||||
return types2.NewParam(pos, r.currPkg, name, typ)
|
||||
}
|
||||
|
||||
func (r *importReader) bool() bool {
|
||||
return r.uint64() != 0
|
||||
}
|
||||
|
||||
func (r *importReader) int64() int64 {
|
||||
n, err := binary.ReadVarint(&r.declReader)
|
||||
if err != nil {
|
||||
errorf("readVarint: %v", err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (r *importReader) uint64() uint64 {
|
||||
n, err := binary.ReadUvarint(&r.declReader)
|
||||
if err != nil {
|
||||
errorf("readUvarint: %v", err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (r *importReader) byte() byte {
|
||||
x, err := r.declReader.ReadByte()
|
||||
if err != nil {
|
||||
errorf("declReader.ReadByte: %v", err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func baseType(typ types2.Type) *types2.Named {
|
||||
// pointer receivers are never types2.Named types
|
||||
if p, _ := typ.(*types2.Pointer); p != nil {
|
||||
typ = p.Elem()
|
||||
}
|
||||
// receiver base types are always (possibly generic) types2.Named types
|
||||
n, _ := typ.(*types2.Named)
|
||||
return n
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// package importer implements package reading for gc-generated object files.
|
||||
package importer
|
||||
|
||||
import (
|
||||
|
@ -209,6 +209,7 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi
|
||||
|
||||
switch hdr {
|
||||
case "$$\n":
|
||||
// TODO(taking): 's/(recompile library)/(recompile package)/g'.
|
||||
err = fmt.Errorf("import %q: old textual export format no longer supported (recompile library)", path)
|
||||
|
||||
case "$$B\n":
|
||||
|
Loading…
Reference in New Issue
Block a user