"cmd/compile/internal/big"
"encoding/binary"
"fmt"
+ "strconv"
+ "strings"
)
// The overall structure of Import is symmetric to Export: For each
// changes to bimport.go and bexport.go.
type importer struct {
- in *bufio.Reader
- buf []byte // reused for reading strings
+ in *bufio.Reader
+ buf []byte // reused for reading strings
+ version int // export format version
// object lists, in order of deserialization
strList []string
func Import(in *bufio.Reader) {
p := importer{
in: in,
+ version: -1, // unknown version
strList: []string{""}, // empty string is mapped to 0
}
// 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).
}
p.trackAllTypes = p.rawByte() == 'a'
p.posInfoFormat = p.bool()
- const go17version = "v1"
- if s := p.string(); s != go17version {
- Fatalf("importer: unknown export data format: %s (imported package compiled with old compiler?)", s)
+ versionstr = p.string()
+ if versionstr == "v1" {
+ p.version = 0
}
} else {
// Go1.8 extensible encoding
- if s := p.rawStringln(b); s != exportVersion {
- Fatalf("importer: unknown export data format: %s (imported package compiled with old compiler?)", s)
+ // 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
+ }
}
+ }
+
+ // read version specific flags - extend as necessary
+ switch p.version {
+ // case 2:
+ // ...
+ // fallthrough
+ case 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.bool()
p.posInfoFormat = p.bool()
+ case 0:
+ // Go1.7 encoding format - nothing to do here
+ default:
+ formatErrorf("unknown export format version %d (%q)", p.version, versionstr)
}
// --- generic export data ---
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d objects; want %d", objcount, count)
+ formatErrorf("got %d objects; want %d", objcount, count)
}
// --- compiler-specific export data ---
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d objects; want %d", objcount, count)
+ formatErrorf("got %d objects; want %d", objcount, count)
}
// read inlineable functions bodies
if dclcontext != PEXTERN {
- Fatalf("importer: unexpected context %d", dclcontext)
+ formatErrorf("unexpected context %d", dclcontext)
}
objcount = 0
// don't process the same function twice
if i <= i0 {
- Fatalf("importer: index not increasing: %d <= %d", i, i0)
+ formatErrorf("index not increasing: %d <= %d", i, i0)
}
i0 = i
if Funcdepth != 0 {
- Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
+ formatErrorf("unexpected Funcdepth %d", Funcdepth)
}
// Note: In the original code, funchdr and funcbody are called for
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d functions; want %d", objcount, count)
+ formatErrorf("got %d functions; want %d", objcount, count)
}
if dclcontext != PEXTERN {
- Fatalf("importer: unexpected context %d", dclcontext)
+ formatErrorf("unexpected context %d", dclcontext)
}
p.verifyTypes()
testdclstack() // debugging only
}
+func formatErrorf(format string, args ...interface{}) {
+ if debugFormat {
+ Fatalf(format, args...)
+ }
+
+ Yyerror("cannot import %q due to version skew - reinstall package (%s)",
+ importpkg.Path, fmt.Sprintf(format, args...))
+ errorexit()
+}
+
func (p *importer) verifyTypes() {
for _, pair := range p.cmpList {
pt := pair.pt
t := pair.t
if !Eqtype(pt.Orig, t) {
- // TODO(gri) Is this a possible regular error (stale files)
- // or can this only happen if export/import is flawed?
- // (if the latter, change to Fatalf here)
- Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
+ formatErrorf("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
}
}
}
// otherwise, i is the package tag (< 0)
if i != packageTag {
- Fatalf("importer: expected package tag, found tag = %d", i)
+ formatErrorf("expected package tag, found tag = %d", i)
}
// read package data
// we should never see an empty package name
if name == "" {
- Fatalf("importer: empty package name for path %q", path)
+ formatErrorf("empty package name for path %q", path)
}
// we should never see a bad import path
if isbadimport(path) {
- Fatalf("importer: bad package path %q for package %s", path, name)
+ formatErrorf("bad package path %q for package %s", path, name)
}
// an empty path denotes the package we are currently importing;
// it must be the first package we see
if (path == "") != (len(p.pkgList) == 0) {
- Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
+ formatErrorf("package path %q for pkg index %d", path, len(p.pkgList))
}
// add package to pkgList
pkg.Name = name
numImport[name]++
} else if pkg.Name != name {
- Yyerror("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
+ Yyerror("conflicting package names %s and %s for path %q", pkg.Name, name, path)
}
if incannedimport == 0 && myimportpath != "" && path == myimportpath {
Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
if sym.Def != nil && sym.Def.Op == ONAME {
// function was imported before (via another import)
if !Eqtype(sig, sym.Def.Type) {
- Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
+ formatErrorf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
}
p.funcList = append(p.funcList, nil)
break
}
default:
- Fatalf("importer: unexpected object (tag = %d)", tag)
+ formatErrorf("unexpected object (tag = %d)", tag)
}
}
case interfaceTag:
t = p.newtyp(TINTER)
if p.int() != 0 {
- Fatalf("importer: unexpected embedded interface")
+ formatErrorf("unexpected embedded interface")
}
tointerface0(t, p.methodList())
ct.Elem = p.typ()
default:
- Fatalf("importer: unexpected type (tag = %d)", i)
+ formatErrorf("unexpected type (tag = %d)", i)
}
if t == nil {
- Fatalf("importer: nil type (type tag = %d)", i)
+ formatErrorf("nil type (type tag = %d)", i)
}
return t
if named {
name := p.string()
if name == "" {
- Fatalf("importer: expected named parameter")
+ formatErrorf("expected named parameter")
}
// TODO(gri) Supply function/method package rather than
// encoding the package for each parameter repeatedly.
x.U = p.string()
case unknownTag:
- Fatalf("importer: unknown constant (importing package with errors)")
+ formatErrorf("unknown constant (importing package with errors)")
case nilTag:
x.U = new(NilVal)
default:
- Fatalf("importer: unexpected value tag %d", tag)
+ formatErrorf("unexpected value tag %d", tag)
}
// verify ideal type
if typ.IsUntyped() && untype(x.Ctype()) != typ {
- Fatalf("importer: value %v and type %v don't match", x, typ)
+ formatErrorf("value %v and type %v don't match", x, typ)
}
return
func (p *importer) int() int {
x := p.int64()
if int64(int(x)) != x {
- Fatalf("importer: exported integer too large")
+ formatErrorf("exported integer too large")
}
return int(x)
}
func (p *importer) marker(want byte) {
if got := p.rawByte(); got != want {
- Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
+ formatErrorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
pos := p.read
if n := int(p.rawInt64()); n != pos {
- Fatalf("importer: incorrect position: got %d; want %d", n, pos)
+ formatErrorf("incorrect position: got %d; want %d", n, pos)
}
}
func (p *importer) rawInt64() int64 {
i, err := binary.ReadVarint(p)
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
return i
}
c, err := p.in.ReadByte()
p.read++
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
if c == '|' {
c, err = p.in.ReadByte()
p.read++
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
switch c {
case 'S':
case '|':
// nothing to do
default:
- Fatalf("importer: unexpected escape sequence in export data")
+ formatErrorf("unexpected escape sequence in export data")
}
}
return c