summaryrefslogtreecommitdiff
path: root/libgo/go/go/internal/gcimporter/bimport.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/go/internal/gcimporter/bimport.go')
-rw-r--r--libgo/go/go/internal/gcimporter/bimport.go588
1 files changed, 428 insertions, 160 deletions
diff --git a/libgo/go/go/internal/gcimporter/bimport.go b/libgo/go/go/internal/gcimporter/bimport.go
index 68690424a1..a8f349052a 100644
--- a/libgo/go/go/internal/gcimporter/bimport.go
+++ b/libgo/go/go/internal/gcimporter/bimport.go
@@ -11,100 +11,140 @@ import (
"go/token"
"go/types"
"sort"
+ "strconv"
+ "strings"
+ "sync"
"unicode"
"unicode/utf8"
)
+type importer struct {
+ imports map[string]*types.Package
+ data []byte
+ path string
+ buf []byte // for reading strings
+ version int // export format version
+
+ // object lists
+ strList []string // in order of appearance
+ pkgList []*types.Package // in order of appearance
+ typList []types.Type // in order of appearance
+ trackAllTypes bool
+
+ // position encoding
+ posInfoFormat bool
+ prevFile string
+ prevLine int
+ fset *token.FileSet
+ files map[string]*token.File
+
+ // debugging support
+ debugFormat bool
+ read int // bytes read
+}
+
// BImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
-// If data is obviously malformed, an error is returned but in
-// general it is not recommended to call BImportData on untrusted data.
-func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
+// If the export data version is not recognized or the format is otherwise
+// compromised, an error is returned.
+func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, _ *types.Package, err error) {
+ // catch panics and return them as errors
+ defer func() {
+ if e := recover(); e != nil {
+ // The package (filename) causing the problem is added to this
+ // error by a wrapper in the caller (Import in gcimporter.go).
+ err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e)
+ }
+ }()
+
p := importer{
imports: imports,
data: data,
+ path: path,
+ version: -1, // unknown version
+ strList: []string{""}, // empty string is mapped to 0
+ fset: fset,
+ files: make(map[string]*token.File),
+ }
+
+ // read version info
+ var versionstr string
+ if b := p.rawByte(); b == 'c' || b == 'd' {
+ // Go1.7 encoding; first byte encodes low-level
+ // encoding format (compact vs debug).
+ // For backward-compatibility only (avoid problems with
+ // old installed packages). Newly compiled packages use
+ // the extensible format string.
+ // TODO(gri) Remove this support eventually; after Go1.8.
+ if b == 'd' {
+ p.debugFormat = true
+ }
+ p.trackAllTypes = p.rawByte() == 'a'
+ p.posInfoFormat = p.int() != 0
+ versionstr = p.string()
+ if versionstr == "v1" {
+ p.version = 0
+ }
+ } else {
+ // Go1.8 extensible encoding
+ // read version string and extract version number (ignore anything after the version number)
+ versionstr = p.rawStringln(b)
+ if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
+ if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
+ p.version = v
+ }
+ }
}
- p.buf = p.bufarray[:]
- // read low-level encoding format
- switch format := p.byte(); format {
- case 'c':
- // compact format - nothing to do
- case 'd':
- p.debugFormat = true
+ // read version specific flags - extend as necessary
+ switch p.version {
+ // case 4:
+ // ...
+ // fallthrough
+ case 3, 2, 1:
+ p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
+ p.trackAllTypes = p.int() != 0
+ p.posInfoFormat = p.int() != 0
+ case 0:
+ // Go1.7 encoding format - nothing to do here
default:
- return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ errorf("unknown export format version %d (%q)", p.version, versionstr)
}
// --- generic export data ---
- if v := p.string(); v != "v0" {
- return p.read, nil, fmt.Errorf("unknown version: %s", v)
- }
-
// populate typList with predeclared "known" types
p.typList = append(p.typList, predeclared...)
// read package data
- // TODO(gri) clean this up
- i := p.tagOrIndex()
- if i != packageTag {
- panic(fmt.Sprintf("package tag expected, got %d", i))
- }
- name := p.string()
- if s := p.string(); s != "" {
- panic(fmt.Sprintf("empty path expected, got %s", s))
- }
- pkg := p.imports[path]
- if pkg == nil {
- pkg = types.NewPackage(path, name)
- p.imports[path] = pkg
- }
- p.pkgList = append(p.pkgList, pkg)
-
- if debug && p.pkgList[0] != pkg {
- panic("imported packaged not found in pkgList[0]")
- }
-
- // read compiler-specific flags
- p.string() // discard
-
- // read consts
- for i := p.int(); i > 0; i-- {
- name := p.string()
- typ := p.typ(nil)
- val := p.value()
- p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
- }
-
- // read vars
- for i := p.int(); i > 0; i-- {
- name := p.string()
- typ := p.typ(nil)
- p.declare(types.NewVar(token.NoPos, pkg, name, typ))
- }
-
- // read funcs
- for i := p.int(); i > 0; i-- {
- name := p.string()
- sig := p.typ(nil).(*types.Signature)
- p.int() // read and discard index of inlined function body
- p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+ pkg := p.pkg()
+
+ // read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
+ objcount := 0
+ for {
+ tag := p.tagOrIndex()
+ if tag == endTag {
+ break
+ }
+ p.obj(tag)
+ objcount++
}
- // read types
- for i := p.int(); i > 0; i-- {
- // name is parsed as part of named type and the
- // type object is added to scope via respective
- // named type
- _ = p.typ(nil).(*types.Named)
+ // self-verification
+ if count := p.int(); count != objcount {
+ errorf("got %d objects; want %d", objcount, count)
}
// ignore compiler-specific import data
// complete interfaces
for _, typ := range p.typList {
- if it, ok := typ.(*types.Interface); ok {
+ // If we only record named types (!p.trackAllTypes),
+ // we must check the underlying types here. If we
+ // track all types, the Underlying() method call is
+ // not needed.
+ // TODO(gri) Remove if p.trackAllTypes is gone.
+ if it, ok := typ.Underlying().(*types.Interface); ok {
it.Complete()
}
}
@@ -120,23 +160,8 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
return p.read, pkg, nil
}
-type importer struct {
- imports map[string]*types.Package
- data []byte
- buf []byte // for reading strings
- bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
- pkgList []*types.Package
- typList []types.Type
-
- debugFormat bool
- read int // bytes read
-}
-
-func (p *importer) declare(obj types.Object) {
- if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
- // This can only happen if we import a package a second time.
- panic(fmt.Sprintf("%s already declared", alt.Name()))
- }
+func errorf(format string, args ...interface{}) {
+ panic(fmt.Sprintf(format, args...))
}
func (p *importer) pkg() *types.Package {
@@ -148,7 +173,7 @@ func (p *importer) pkg() *types.Package {
// otherwise, i is the package tag (< 0)
if i != packageTag {
- panic(fmt.Sprintf("unexpected package tag %d", i))
+ errorf("unexpected package tag %d", i)
}
// read package data
@@ -157,25 +182,179 @@ func (p *importer) pkg() *types.Package {
// we should never see an empty package name
if name == "" {
- panic("empty package name in import")
+ errorf("empty package name in import")
}
- // we should never see an empty import path
- if path == "" {
- panic("empty import path")
+ // an empty path denotes the package we are currently importing;
+ // it must be the first package we see
+ if (path == "") != (len(p.pkgList) == 0) {
+ errorf("package path %q for pkg index %d", path, len(p.pkgList))
}
// if the package was imported before, use that one; otherwise create a new one
+ if path == "" {
+ path = p.path
+ }
pkg := p.imports[path]
if pkg == nil {
pkg = types.NewPackage(path, name)
p.imports[path] = pkg
+ } else if pkg.Name() != name {
+ errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path)
}
p.pkgList = append(p.pkgList, pkg)
return pkg
}
+// objTag returns the tag value for each object kind.
+// obj must not be a *types.Alias.
+func objTag(obj types.Object) int {
+ switch obj.(type) {
+ case *types.Const:
+ return constTag
+ case *types.TypeName:
+ return typeTag
+ case *types.Var:
+ return varTag
+ case *types.Func:
+ return funcTag
+ // Aliases are not exported multiple times, thus we should not see them here.
+ default:
+ errorf("unexpected object: %v (%T)", obj, obj) // panics
+ panic("unreachable")
+ }
+}
+
+func sameObj(a, b types.Object) bool {
+ // Because unnamed types are not canonicalized, we cannot simply compare types for
+ // (pointer) identity.
+ // Ideally we'd check equality of constant values as well, but this is good enough.
+ return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
+}
+
+func (p *importer) declare(obj types.Object) {
+ pkg := obj.Pkg()
+ if alt := pkg.Scope().Insert(obj); alt != nil {
+ // This can only trigger if we import a (non-type) object a second time.
+ // Excluding aliases, this cannot happen because 1) we only import a package
+ // once; and b) we ignore compiler-specific export data which may contain
+ // functions whose inlined function bodies refer to other functions that
+ // were already imported.
+ // However, aliases require reexporting the original object, so we need
+ // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go,
+ // method importer.obj, switch case importing functions).
+ // Note that the original itself cannot be an alias.
+ if !sameObj(obj, alt) {
+ errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
+ }
+ }
+}
+
+func (p *importer) obj(tag int) {
+ switch tag {
+ case constTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ typ := p.typ(nil)
+ val := p.value()
+ p.declare(types.NewConst(pos, pkg, name, typ, val))
+
+ case typeTag:
+ p.typ(nil)
+
+ case varTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ typ := p.typ(nil)
+ p.declare(types.NewVar(pos, pkg, name, typ))
+
+ case funcTag:
+ pos := p.pos()
+ pkg, name := p.qualifiedName()
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ sig := types.NewSignature(nil, params, result, isddd)
+ p.declare(types.NewFunc(pos, pkg, name, sig))
+
+ case aliasTag:
+ pos := p.pos()
+ name := p.string()
+ var orig types.Object
+ if pkg, name := p.qualifiedName(); pkg != nil {
+ orig = pkg.Scope().Lookup(name)
+ }
+ // Alias-related code. Keep for now.
+ _ = pos
+ _ = name
+ _ = orig
+ // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig))
+
+ default:
+ errorf("unexpected object tag %d", tag)
+ }
+}
+
+func (p *importer) pos() token.Pos {
+ if !p.posInfoFormat {
+ return token.NoPos
+ }
+
+ file := p.prevFile
+ line := p.prevLine
+ if delta := p.int(); delta != 0 {
+ // line changed
+ line += delta
+ } else if n := p.int(); n >= 0 {
+ // file changed
+ file = p.prevFile[:n] + p.string()
+ p.prevFile = file
+ line = p.int()
+ }
+ p.prevLine = line
+
+ // Synthesize a token.Pos
+
+ // Since we don't know the set of needed file positions, we
+ // reserve maxlines positions per file.
+ const maxlines = 64 * 1024
+ f := p.files[file]
+ if f == nil {
+ f = p.fset.AddFile(file, -1, maxlines)
+ p.files[file] = f
+ // Allocate the fake linebreak indices on first use.
+ // TODO(adonovan): opt: save ~512KB using a more complex scheme?
+ fakeLinesOnce.Do(func() {
+ fakeLines = make([]int, maxlines)
+ for i := range fakeLines {
+ fakeLines[i] = i
+ }
+ })
+ f.SetLines(fakeLines)
+ }
+
+ if line > maxlines {
+ line = 1
+ }
+
+ // Treat the file as if it contained only newlines
+ // and column=1: use the line number as the offset.
+ return f.Pos(line - 1)
+}
+
+var (
+ fakeLines []int
+ fakeLinesOnce sync.Once
+)
+
+func (p *importer) qualifiedName() (pkg *types.Package, name string) {
+ name = p.string()
+ if name != "" {
+ pkg = p.pkg()
+ }
+ return
+}
+
func (p *importer) record(t types.Type) {
p.typList = append(p.typList, t)
}
@@ -205,19 +384,19 @@ func (p *importer) typ(parent *types.Package) types.Type {
switch i {
case namedTag:
// read type object
- name := p.string()
- parent = p.pkg()
+ pos := p.pos()
+ parent, name := p.qualifiedName()
scope := parent.Scope()
obj := scope.Lookup(name)
// if the object doesn't exist yet, create and insert it
if obj == nil {
- obj = types.NewTypeName(token.NoPos, parent, name, nil)
+ obj = types.NewTypeName(pos, parent, name, nil)
scope.Insert(obj)
}
if _, ok := obj.(*types.TypeName); !ok {
- panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj))
+ errorf("pkg = %s, name = %s => %s", parent, name, obj)
}
// associate new named type with obj if it doesn't exist yet
@@ -231,26 +410,35 @@ func (p *importer) typ(parent *types.Package) types.Type {
t0.SetUnderlying(p.typ(parent))
// interfaces don't have associated methods
- if _, ok := t0.Underlying().(*types.Interface); ok {
+ if types.IsInterface(t0) {
return t
}
// read associated methods
for i := p.int(); i > 0; i-- {
+ // TODO(gri) replace this with something closer to fieldName
+ pos := p.pos()
name := p.string()
+ if !exported(name) {
+ p.pkg()
+ }
+
recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params, isddd := p.paramList()
result, _ := p.paramList()
- p.int() // read and discard index of inlined function body
+ p.int() // go:nointerface pragma - discarded
+
sig := types.NewSignature(recv.At(0), params, result, isddd)
- t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
+ t0.AddMethod(types.NewFunc(pos, parent, name, sig))
}
return t
case arrayTag:
t := new(types.Array)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
n := p.int64()
*t = *types.NewArray(p.typ(parent), n)
@@ -258,42 +446,45 @@ func (p *importer) typ(parent *types.Package) types.Type {
case sliceTag:
t := new(types.Slice)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
*t = *types.NewSlice(p.typ(parent))
return t
case dddTag:
t := new(dddSlice)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
t.elem = p.typ(parent)
return t
case structTag:
t := new(types.Struct)
- p.record(t)
-
- n := p.int()
- fields := make([]*types.Var, n)
- tags := make([]string, n)
- for i := range fields {
- fields[i] = p.field(parent)
- tags[i] = p.string()
+ if p.trackAllTypes {
+ p.record(t)
}
- *t = *types.NewStruct(fields, tags)
+
+ *t = *types.NewStruct(p.fieldList(parent))
return t
case pointerTag:
t := new(types.Pointer)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
*t = *types.NewPointer(p.typ(parent))
return t
case signatureTag:
t := new(types.Signature)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
params, isddd := p.paramList()
result, _ := p.paramList()
@@ -306,30 +497,26 @@ func (p *importer) typ(parent *types.Package) types.Type {
// such cycle must contain a named type which would have been
// first defined earlier.
n := len(p.typList)
- p.record(nil)
+ if p.trackAllTypes {
+ p.record(nil)
+ }
// no embedded interfaces with gc compiler
if p.int() != 0 {
- panic("unexpected embedded interface")
+ errorf("unexpected embedded interface")
}
- // read methods
- methods := make([]*types.Func, p.int())
- for i := range methods {
- pkg, name := p.fieldName(parent)
- params, isddd := p.paramList()
- result, _ := p.paramList()
- sig := types.NewSignature(nil, params, result, isddd)
- methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
+ t := types.NewInterface(p.methodList(parent), nil)
+ if p.trackAllTypes {
+ p.typList[n] = t
}
-
- t := types.NewInterface(methods, nil)
- p.typList[n] = t
return t
case mapTag:
t := new(types.Map)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
key := p.typ(parent)
val := p.typ(parent)
@@ -338,7 +525,9 @@ func (p *importer) typ(parent *types.Package) types.Type {
case chanTag:
t := new(types.Chan)
- p.record(t)
+ if p.trackAllTypes {
+ p.record(t)
+ }
var dir types.ChanDir
// tag values must match the constants in cmd/compile/internal/gc/go.go
@@ -350,18 +539,32 @@ func (p *importer) typ(parent *types.Package) types.Type {
case 3 /* Cboth */ :
dir = types.SendRecv
default:
- panic(fmt.Sprintf("unexpected channel dir %d", d))
+ errorf("unexpected channel dir %d", d)
}
val := p.typ(parent)
*t = *types.NewChan(dir, val)
return t
default:
- panic(fmt.Sprintf("unexpected type tag %d", i))
+ errorf("unexpected type tag %d", i) // panics
+ panic("unreachable")
}
}
+func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) {
+ if n := p.int(); n > 0 {
+ fields = make([]*types.Var, n)
+ tags = make([]string, n)
+ for i := range fields {
+ fields[i] = p.field(parent)
+ tags[i] = p.string()
+ }
+ }
+ return
+}
+
func (p *importer) field(parent *types.Package) *types.Var {
+ pos := p.pos()
pkg, name := p.fieldName(parent)
typ := p.typ(parent)
@@ -375,28 +578,47 @@ func (p *importer) field(parent *types.Package) *types.Var {
case *types.Named:
name = typ.Obj().Name()
default:
- panic("anonymous field expected")
+ errorf("anonymous field expected")
}
anonymous = true
}
- return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+ return types.NewField(pos, pkg, name, typ, anonymous)
+}
+
+func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
+ if n := p.int(); n > 0 {
+ methods = make([]*types.Func, n)
+ for i := range methods {
+ methods[i] = p.method(parent)
+ }
+ }
+ return
+}
+
+func (p *importer) method(parent *types.Package) *types.Func {
+ pos := p.pos()
+ pkg, name := p.fieldName(parent)
+ params, isddd := p.paramList()
+ result, _ := p.paramList()
+ sig := types.NewSignature(nil, params, result, isddd)
+ return types.NewFunc(pos, pkg, name, sig)
}
func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
+ name := p.string()
pkg := parent
if pkg == nil {
// use the imported package instead
pkg = p.pkgList[0]
}
- name := p.string()
- if name == "" {
- return pkg, "" // anonymous
+ if p.version == 0 && name == "_" {
+ // version 0 didn't export a package for _ fields
+ return pkg, name
}
- if name == "?" || name != "_" && !exported(name) {
- // explicitly qualified field
+ if name != "" && !exported(name) {
if name == "?" {
- name = "" // anonymous
+ name = ""
}
pkg = p.pkg()
}
@@ -430,18 +652,25 @@ func (p *importer) param(named bool) (*types.Var, bool) {
t = types.NewSlice(td.elem)
}
+ var pkg *types.Package
var name string
if named {
name = p.string()
if name == "" {
- panic("expected named parameter")
+ errorf("expected named parameter")
+ }
+ if name != "_" {
+ pkg = p.pkg()
+ }
+ if i := strings.Index(name, "ยท"); i > 0 {
+ name = name[:i] // cut off gc-specific parameter numbering
}
}
// read and discard compiler-specific info
p.string()
- return types.NewVar(token.NoPos, nil, name, t), isddd
+ return types.NewVar(token.NoPos, pkg, name, t), isddd
}
func exported(name string) bool {
@@ -465,8 +694,11 @@ func (p *importer) value() constant.Value {
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
case stringTag:
return constant.MakeString(p.string())
+ case unknownTag:
+ return constant.MakeUnknown()
default:
- panic(fmt.Sprintf("unexpected value tag %d", tag))
+ errorf("unexpected value tag %d", tag) // panics
+ panic("unreachable")
}
}
@@ -529,7 +761,7 @@ func (p *importer) tagOrIndex() int {
func (p *importer) int() int {
x := p.int64()
if int64(int(x)) != x {
- panic("exported integer too large")
+ errorf("exported integer too large")
}
return int(x)
}
@@ -546,50 +778,65 @@ func (p *importer) string() string {
if p.debugFormat {
p.marker('s')
}
-
- if n := int(p.rawInt64()); n > 0 {
- if cap(p.buf) < n {
- p.buf = make([]byte, n)
- } else {
- p.buf = p.buf[:n]
- }
- for i := 0; i < n; i++ {
- p.buf[i] = p.byte()
- }
- return string(p.buf)
+ // if the string was seen before, i is its index (>= 0)
+ // (the empty string is at index 0)
+ i := p.rawInt64()
+ if i >= 0 {
+ return p.strList[i]
}
-
- return ""
+ // otherwise, i is the negative string length (< 0)
+ if n := int(-i); n <= cap(p.buf) {
+ p.buf = p.buf[:n]
+ } else {
+ p.buf = make([]byte, n)
+ }
+ for i := range p.buf {
+ p.buf[i] = p.rawByte()
+ }
+ s := string(p.buf)
+ p.strList = append(p.strList, s)
+ return s
}
func (p *importer) marker(want byte) {
- if got := p.byte(); got != want {
- panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
+ if got := p.rawByte(); got != want {
+ errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
pos := p.read
if n := int(p.rawInt64()); n != pos {
- panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+ errorf("incorrect position: got %d; want %d", n, pos)
}
}
-// rawInt64 should only be used by low-level decoders
+// rawInt64 should only be used by low-level decoders.
func (p *importer) rawInt64() int64 {
i, err := binary.ReadVarint(p)
if err != nil {
- panic(fmt.Sprintf("read error: %v", err))
+ errorf("read error: %v", err)
}
return i
}
+// rawStringln should only be used to read the initial version string.
+func (p *importer) rawStringln(b byte) string {
+ p.buf = p.buf[:0]
+ for b != '\n' {
+ p.buf = append(p.buf, b)
+ b = p.rawByte()
+ }
+ return string(p.buf)
+}
+
// needed for binary.ReadVarint in rawInt64
func (p *importer) ReadByte() (byte, error) {
- return p.byte(), nil
+ return p.rawByte(), nil
}
// byte is the bottleneck interface for reading p.data.
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
-func (p *importer) byte() byte {
+// rawByte should only be used by low-level decoders.
+func (p *importer) rawByte() byte {
b := p.data[0]
r := 1
if b == '|' {
@@ -601,7 +848,7 @@ func (p *importer) byte() byte {
case '|':
// nothing to do
default:
- panic("unexpected escape sequence in export data")
+ errorf("unexpected escape sequence in export data")
}
}
p.data = p.data[r:]
@@ -615,8 +862,13 @@ func (p *importer) byte() byte {
// Tags. Must be < 0.
const (
- // Packages
+ // Objects
packageTag = -(iota + 1)
+ constTag
+ typeTag
+ varTag
+ funcTag
+ endTag
// Types
namedTag
@@ -638,6 +890,11 @@ const (
fractionTag // not used by gc
complexTag
stringTag
+ nilTag // only used by gc (appears in exported inlined function bodies)
+ unknownTag // not used by gc (only appears in packages with errors)
+
+ // Aliases
+ aliasTag
)
var predeclared = []types.Type{
@@ -678,4 +935,15 @@ var predeclared = []types.Type{
// package unsafe
types.Typ[types.UnsafePointer],
+
+ // invalid type
+ types.Typ[types.Invalid], // only appears in packages with errors
+
+ // used internally by gc; never used by this package or in .a files
+ anyType{},
}
+
+type anyType struct{}
+
+func (t anyType) Underlying() types.Type { return t }
+func (t anyType) String() string { return "any" }