mirror of
https://github.com/golang/go
synced 2024-11-18 14:04:45 -07:00
go/gcimporter15: support invalid types and constants in binary export data
Although invalid types and unknown constant values should never appear in .a files (since gc will stop with an error before writing export data), they can now be faithfully encoded and decoded. This makes the protocol robust for IDE-like applications that must deal with incomplete or incorrect programs. (Corresponding std lib CL: https://go-review.googlesource.com/20828) Change-Id: I539ffd951b90f01705a7f23ec778c623c729d9a0 Reviewed-on: https://go-review.googlesource.com/20827 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
758728c4b2
commit
8a9be374d7
@ -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",
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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],
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user