diff --git a/go/gcimporter15/bexport.go b/go/gcimporter15/bexport.go index 8eb048eb..36bcf035 100644 --- a/go/gcimporter15/bexport.go +++ b/go/gcimporter15/bexport.go @@ -32,9 +32,6 @@ const ( ) // BExportData returns binary export data for pkg. -// -// It is not safe to call this function on a package containing errors. -// TODO(adonovan): add InvalidType to the protocol and lift this restriction. func BExportData(pkg *types.Package) []byte { p := exporter{ pkgIndex: make(map[*types.Package]int), @@ -209,9 +206,6 @@ func (p *exporter) typ(t types.Type) { if t == nil { log.Fatalf("nil type") } - if t == types.Typ[types.Invalid] { - log.Fatal("BExportData invoked on package with errors") - } // Possible optimization: Anonymous pointer types *T where // T is a named type are common. We could canonicalize all @@ -489,6 +483,10 @@ func (p *exporter) value(x constant.Value) { p.tag(stringTag) p.string(constant.StringVal(x)) + case constant.Unknown: + // (Package contains type errors.) + p.tag(unknownTag) + default: log.Fatalf("unexpected value %v (%T)", x, x) } @@ -700,4 +698,5 @@ var tagString = [...]string{ -fractionTag: "fraction", -complexTag: "complex", -stringTag: "string", + -unknownTag: "unknown", } diff --git a/go/gcimporter15/bexport_test.go b/go/gcimporter15/bexport_test.go index fea4536f..941f7515 100644 --- a/go/gcimporter15/bexport_test.go +++ b/go/gcimporter15/bexport_test.go @@ -30,11 +30,25 @@ func TestBExportData_stdlib(t *testing.T) { // Load, parse and type-check the program. ctxt := build.Default // copy ctxt.GOPATH = "" // disable GOPATH - conf := loader.Config{Build: &ctxt} + conf := loader.Config{ + Build: &ctxt, + AllowErrors: true, + } for _, path := range buildutil.AllPackages(conf.Build) { conf.Import(path) } + // Create a package containing type and value errors to ensure + // they are properly encoded/decoded. + f, err := conf.ParseFile("haserrors/haserrors.go", `package haserrors +const UnknownValue = "" + 0 +type UnknownType undefined +`) + if err != nil { + t.Fatal(err) + } + conf.CreateFromFiles("haserrors", f) + prog, err := conf.Load() if err != nil { t.Fatalf("Load failed: %v", err) @@ -49,7 +63,6 @@ func TestBExportData_stdlib(t *testing.T) { if info.Files == nil { continue // empty directory } - exportdata := gcimporter.BExportData(pkg) imports := make(map[string]*types.Package) diff --git a/go/gcimporter15/bimport.go b/go/gcimporter15/bimport.go index 0ec216e9..a39e3261 100644 --- a/go/gcimporter15/bimport.go +++ b/go/gcimporter15/bimport.go @@ -471,6 +471,9 @@ func (p *importer) value() constant.Value { return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) case stringTag: return constant.MakeString(p.string()) + case unknownTag: + // (Encoded package contains type errors.) + return constant.MakeUnknown() default: panic(fmt.Sprintf("unexpected value tag %d", tag)) } @@ -644,6 +647,7 @@ const ( fractionTag // not used by gc complexTag stringTag + unknownTag // only appears in packages with errors ) var predeclared = []types.Type{ @@ -685,7 +689,10 @@ var predeclared = []types.Type{ // package unsafe types.Typ[types.UnsafePointer], - // any type, for builtin export data + // invalid type + types.Typ[types.Invalid], // only appears in packages with errors + // TODO(mdempsky): Provide an actual Type value to represent "any"? + // (Why exactly does gc emit the "any" type?) types.Typ[types.Invalid], }