2020-10-19 15:28:22 -07:00
|
|
|
// UNREVIEWED
|
|
|
|
|
// 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/gc/iexport.go for the export data format.
|
|
|
|
|
|
|
|
|
|
package importer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"cmd/compile/internal/syntax"
|
|
|
|
|
"cmd/compile/internal/types2"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"fmt"
|
|
|
|
|
"go/constant"
|
|
|
|
|
"go/token"
|
|
|
|
|
"io"
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
"math/big"
|
2020-10-19 15:28:22 -07:00
|
|
|
"sort"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type intReader struct {
|
|
|
|
|
*bytes.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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const predeclReserved = 32
|
|
|
|
|
|
|
|
|
|
type itag uint64
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// Types
|
|
|
|
|
definedType itag = iota
|
|
|
|
|
pointerType
|
|
|
|
|
sliceType
|
|
|
|
|
arrayType
|
|
|
|
|
chanType
|
|
|
|
|
mapType
|
|
|
|
|
signatureType
|
|
|
|
|
structType
|
|
|
|
|
interfaceType
|
|
|
|
|
)
|
|
|
|
|
|
2020-10-22 15:32:05 -07:00
|
|
|
const io_SeekCurrent = 1 // io.SeekCurrent (not defined in Go 1.4)
|
|
|
|
|
|
2020-10-19 15:28:22 -07:00
|
|
|
// iImportData 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 iImportData(imports map[string]*types2.Package, data []byte, path string) (_ int, pkg *types2.Package, err error) {
|
|
|
|
|
const currentVersion = 1
|
|
|
|
|
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{bytes.NewReader(data), path}
|
|
|
|
|
|
|
|
|
|
version = int64(r.uint64())
|
|
|
|
|
switch version {
|
|
|
|
|
case currentVersion, 0:
|
|
|
|
|
default:
|
|
|
|
|
errorf("unknown iexport format version %d", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sLen := int64(r.uint64())
|
|
|
|
|
dLen := int64(r.uint64())
|
|
|
|
|
|
2020-10-22 15:32:05 -07:00
|
|
|
whence, _ := r.Seek(0, io_SeekCurrent)
|
2020-10-19 15:28:22 -07:00
|
|
|
stringData := data[whence : whence+sLen]
|
|
|
|
|
declData := data[whence+sLen : whence+sLen+dLen]
|
2020-10-22 15:32:05 -07:00
|
|
|
r.Seek(sLen+dLen, io_SeekCurrent)
|
2020-10-19 15:28:22 -07:00
|
|
|
|
|
|
|
|
p := iimporter{
|
|
|
|
|
ipath: path,
|
|
|
|
|
version: int(version),
|
|
|
|
|
|
|
|
|
|
stringData: stringData,
|
|
|
|
|
stringCache: make(map[uint64]string),
|
|
|
|
|
pkgCache: make(map[uint64]*types2.Package),
|
|
|
|
|
|
|
|
|
|
declData: declData,
|
|
|
|
|
pkgIndex: make(map[*types2.Package]map[string]uint64),
|
|
|
|
|
typCache: make(map[uint64]types2.Type),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, pt := range predeclared {
|
|
|
|
|
p.typCache[uint64(i)] = pt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkgList := make([]*types2.Package, r.uint64())
|
|
|
|
|
for i := range pkgList {
|
|
|
|
|
pkgPathOff := r.uint64()
|
|
|
|
|
pkgPath := p.stringAt(pkgPathOff)
|
|
|
|
|
pkgName := p.stringAt(r.uint64())
|
|
|
|
|
_ = r.uint64() // package height; unused by go/types
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, typ := range p.interfaceList {
|
|
|
|
|
typ.Complete()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// record all referenced packages as imports
|
|
|
|
|
list := append(([]*types2.Package)(nil), pkgList[1:]...)
|
|
|
|
|
sort.Sort(byPath(list))
|
|
|
|
|
localpkg.SetImports(list)
|
|
|
|
|
|
|
|
|
|
// package was imported completely and without errors
|
|
|
|
|
localpkg.MarkComplete()
|
|
|
|
|
|
2020-10-22 15:32:05 -07:00
|
|
|
consumed, _ := r.Seek(0, io_SeekCurrent)
|
2020-10-19 15:28:22 -07:00
|
|
|
return int(consumed), localpkg, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type iimporter struct {
|
|
|
|
|
ipath string
|
|
|
|
|
version int
|
|
|
|
|
|
|
|
|
|
stringData []byte
|
|
|
|
|
stringCache map[uint64]string
|
|
|
|
|
pkgCache map[uint64]*types2.Package
|
|
|
|
|
|
|
|
|
|
declData []byte
|
|
|
|
|
pkgIndex map[*types2.Package]map[string]uint64
|
|
|
|
|
typCache map[uint64]types2.Type
|
|
|
|
|
|
|
|
|
|
interfaceList []*types2.Interface
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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}
|
2020-10-22 15:32:05 -07:00
|
|
|
// Reader.Reset is not available in Go 1.4.
|
|
|
|
|
// Use bytes.NewReader for now.
|
|
|
|
|
// r.declReader.Reset(p.declData[off:])
|
|
|
|
|
r.declReader = *bytes.NewReader(p.declData[off:])
|
2020-10-19 15:28:22 -07:00
|
|
|
|
|
|
|
|
r.obj(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) stringAt(off uint64) string {
|
|
|
|
|
if s, ok := p.stringCache[off]; ok {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slen, n := binary.Uvarint(p.stringData[off:])
|
|
|
|
|
if n <= 0 {
|
|
|
|
|
errorf("varint failed")
|
|
|
|
|
}
|
|
|
|
|
spos := off + uint64(n)
|
|
|
|
|
s := string(p.stringData[spos : spos+slen])
|
|
|
|
|
p.stringCache[off] = s
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) typAt(off uint64, base *types2.Named) types2.Type {
|
|
|
|
|
if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if off < predeclReserved {
|
|
|
|
|
errorf("predeclared type missing from cache: %v", off)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := &importReader{p: p}
|
2020-10-22 15:32:05 -07:00
|
|
|
// Reader.Reset is not available in Go 1.4.
|
|
|
|
|
// Use bytes.NewReader for now.
|
|
|
|
|
// r.declReader.Reset(p.declData[off-predeclReserved:])
|
|
|
|
|
r.declReader = *bytes.NewReader(p.declData[off-predeclReserved:])
|
2020-10-19 15:28:22 -07:00
|
|
|
t := r.doType(base)
|
|
|
|
|
|
|
|
|
|
if base == nil || !isInterface(t) {
|
|
|
|
|
p.typCache[off] = t
|
|
|
|
|
}
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type importReader struct {
|
|
|
|
|
p *iimporter
|
|
|
|
|
declReader bytes.Reader
|
|
|
|
|
currPkg *types2.Package
|
|
|
|
|
prevFile string
|
|
|
|
|
prevLine int64
|
|
|
|
|
prevColumn int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) obj(name string) {
|
|
|
|
|
tag := r.byte()
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
|
|
|
|
|
switch tag {
|
|
|
|
|
case 'A':
|
|
|
|
|
typ := r.typ()
|
|
|
|
|
|
|
|
|
|
r.declare(types2.NewTypeName(pos, r.currPkg, name, typ))
|
|
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
|
typ, val := r.value()
|
|
|
|
|
|
|
|
|
|
r.declare(types2.NewConst(pos, r.currPkg, name, typ, val))
|
|
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
|
sig := r.signature(nil)
|
|
|
|
|
|
|
|
|
|
r.declare(types2.NewFunc(pos, r.currPkg, name, sig))
|
|
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
|
// 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)
|
|
|
|
|
r.declare(obj)
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
msig := r.signature(recv)
|
|
|
|
|
|
|
|
|
|
named.AddMethod(types2.NewFunc(mpos, r.currPkg, mname, msig))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
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:
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
var x big.Int
|
|
|
|
|
r.mpint(&x, b)
|
|
|
|
|
val = constant.Make(&x)
|
2020-10-19 15:28:22 -07:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
func (r *importReader) mpint(x *big.Int, typ *types2.Basic) {
|
|
|
|
|
signed, maxBytes := intSize(typ)
|
2020-10-19 15:28:22 -07:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
x.SetInt64(v)
|
|
|
|
|
return
|
2020-10-19 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v := -n
|
|
|
|
|
if signed {
|
|
|
|
|
v = -(n &^ 1) >> 1
|
|
|
|
|
}
|
|
|
|
|
if v < 1 || uint(v) > maxBytes {
|
|
|
|
|
errorf("weird decoding: %v, %v => %v", n, signed, v)
|
|
|
|
|
}
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
b := make([]byte, v)
|
|
|
|
|
io.ReadFull(&r.declReader, b)
|
|
|
|
|
x.SetBytes(b)
|
2020-10-19 15:28:22 -07:00
|
|
|
if signed && n&1 != 0 {
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
x.Neg(x)
|
2020-10-19 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
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()))
|
2020-10-19 15:28:22 -07:00
|
|
|
}
|
[dev.typeparams] cmd/compile/internal/importer: adjust importer to match compiler importer
The compiler chooses the literal value export format by type
not by constant.Kind. That is, a floating-point constant is
always exported as a (big) float value, not a (big) rational
value, even though the internal representation may be that
of a rational number. (This is a possibility now that the
compiler also uses the go/constant package.)
Naturally, during import, a floating-point value is read as
a float and represented as a (big) float in go/constant.
The types2 importer (based on the go/types importer) read
the floating-point number elements (mantissa, exponent) but
then constructed the float go/constant value through a series
of elementary operations, typically leading to a rational,
but sometimes even an integer number (e.g. for math.MaxFloat64).
There is no problem with that (the value is the same) but if
we want to impose bitsize limits on overlarge integer values
we quickly run into trouble with large floats represented as
integers.
This change matches the code importing float literals with
the code used by the compiler.
Note: At some point we may want to relax the import/export code
for constant values and export them by representation rather than
by type. As is, we lose accuracy since all floating-point point
values, even the ones internally represented as rational numbers
end up being exported as floating-point numbers.
Change-Id: Ic751b2046a0fd047f751da3d35cbef0a1b5fea3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/288632
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2021-02-01 15:39:42 -08:00
|
|
|
return constant.Make(&f)
|
2020-10-19 15:28:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 {
|
|
|
|
|
return syntax.Pos{}
|
|
|
|
|
}
|
|
|
|
|
// TODO(gri) fix this
|
|
|
|
|
// return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn))
|
|
|
|
|
return syntax.Pos{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.prevFile = r.string()
|
|
|
|
|
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.prevFile = r.string()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) 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)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
methods[i] = types2.NewFunc(mpos, r.currPkg, mname, msig)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typ := types2.NewInterfaceType(methods, embeddeds)
|
|
|
|
|
r.p.interfaceList = append(r.p.interfaceList, typ)
|
|
|
|
|
return typ
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) kind() itag {
|
|
|
|
|
return itag(r.uint64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) signature(recv *types2.Var) *types2.Signature {
|
|
|
|
|
params := r.paramList()
|
|
|
|
|
results := r.paramList()
|
|
|
|
|
variadic := params.Len() > 0 && r.bool()
|
|
|
|
|
return types2.NewSignature(recv, params, results, variadic)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|