From f08d70c2ed47107d9cee59201cba9081790d125b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 2 Nov 2016 15:03:14 -0700 Subject: [PATCH] go/gcimporter15: support export/import of invalid aliases + test Tested on 1.6, 1.7, and 1.8. Fixes golang/go#17731. Change-Id: I06dff4a72ff08ed5e8ae1d23a1e65fe719c03180 Reviewed-on: https://go-review.googlesource.com/32581 Reviewed-by: Matthew Dempsky Reviewed-by: Alan Donovan --- go/gcimporter15/bexport.go | 36 +++++++++---------- go/gcimporter15/bexport18_test.go | 59 +++++++++++++++++++++++++++++++ go/gcimporter15/bimport.go | 16 +++++---- go/gcimporter15/newalias16.go | 13 ++++--- go/gcimporter15/newalias18.go | 4 ++- 5 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 go/gcimporter15/bexport18_test.go diff --git a/go/gcimporter15/bexport.go b/go/gcimporter15/bexport.go index f7615ba4..0395238e 100644 --- a/go/gcimporter15/bexport.go +++ b/go/gcimporter15/bexport.go @@ -177,24 +177,6 @@ func (p *exporter) pkg(pkg *types.Package, emptypath bool) { } func (p *exporter) obj(obj types.Object) { - if orig := original(obj); orig != obj { - if orig == nil { - // invalid alias - don't export for now (issue 17731) - return - } - - if !p.reexported[orig] { - p.obj(orig) - p.reexported[orig] = true - } - - p.tag(aliasTag) - p.pos(obj) - p.string(obj.Name()) - p.qualifiedName(orig) - return - } - switch obj := obj.(type) { case *types.Const: p.tag(constTag) @@ -221,6 +203,20 @@ func (p *exporter) obj(obj types.Object) { p.paramList(sig.Params(), sig.Variadic()) p.paramList(sig.Results(), false) + case *types_Alias: + // make sure the original is exported before the alias + // (if the alias declaration was invalid, orig will be nil) + orig := original(obj) + if orig != nil && !p.reexported[orig] { + p.obj(orig) + p.reexported[orig] = true + } + + p.tag(aliasTag) + p.pos(obj) + p.string(obj.Name()) + p.qualifiedName(orig) + default: log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj) } @@ -280,6 +276,10 @@ func commonPrefixLen(a, b string) int { } func (p *exporter) qualifiedName(obj types.Object) { + if obj == nil { + p.string("") + return + } p.string(obj.Name()) p.pkg(obj.Pkg(), false) } diff --git a/go/gcimporter15/bexport18_test.go b/go/gcimporter15/bexport18_test.go new file mode 100644 index 00000000..e5518938 --- /dev/null +++ b/go/gcimporter15/bexport18_test.go @@ -0,0 +1,59 @@ +// Copyright 2016 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. + +// +build go1.8 + +package gcimporter_test + +import ( + "go/ast" + "go/parser" + "go/token" + "go/types" + "testing" + + gcimporter "golang.org/x/tools/go/gcimporter15" +) + +func TestInvalidAlias(t *testing.T) { + // parse and typecheck + const src = "package p; func InvalidAlias => foo.f" + fset1 := token.NewFileSet() + f, err := parser.ParseFile(fset1, "p.go", src, 0) + if err != nil { + t.Fatal(err) + } + var conf types.Config + pkg, err := conf.Check("p", fset1, []*ast.File{f}, nil) + if err == nil { + t.Fatal("invalid source type-checked without error") + } + if pkg == nil { + t.Fatal("nil package returned") + } + + // export + exportdata := gcimporter.BExportData(fset1, pkg) + + // import + imports := make(map[string]*types.Package) + fset2 := token.NewFileSet() + _, pkg2, err := gcimporter.BImportData(fset2, imports, exportdata, pkg.Path()) + if err != nil { + t.Fatalf("BImportData(%s): %v", pkg.Path(), err) + } + + // pkg2 must contain InvalidAlias as an invalid Alias + obj := pkg2.Scope().Lookup("InvalidAlias") + if obj == nil { + t.Fatal("InvalidAlias not found") + } + alias, ok := obj.(*types.Alias) + if !ok { + t.Fatalf("got %v; want alias", alias) + } + if alias.Type() != types.Typ[types.Invalid] || alias.Orig() != nil { + t.Fatalf("got %v (orig = %v); want invalid alias", alias, alias.Orig()) + } +} diff --git a/go/gcimporter15/bimport.go b/go/gcimporter15/bimport.go index 8e9a6b28..75eacc71 100644 --- a/go/gcimporter15/bimport.go +++ b/go/gcimporter15/bimport.go @@ -282,11 +282,13 @@ func (p *importer) obj(tag int) { p.declare(types.NewFunc(pos, pkg, name, sig)) case aliasTag: - aliasPos := p.pos() - aliasName := p.string() - pkg, name := p.qualifiedName() - obj := pkg.Scope().Lookup(name) - p.declare(newAlias(aliasPos, p.pkgList[0], aliasName,obj)) + pos := p.pos() + name := p.string() + var orig types.Object + if pkg, name := p.qualifiedName(); pkg != nil { + orig = pkg.Scope().Lookup(name) + } + p.declare(types_NewAlias(pos, p.pkgList[0], name, orig)) default: errorf("unexpected object tag %d", tag) @@ -347,7 +349,9 @@ var ( func (p *importer) qualifiedName() (pkg *types.Package, name string) { name = p.string() - pkg = p.pkg() + if name != "" { + pkg = p.pkg() + } return } diff --git a/go/gcimporter15/newalias16.go b/go/gcimporter15/newalias16.go index d36f8589..8ffcbb7d 100644 --- a/go/gcimporter15/newalias16.go +++ b/go/gcimporter15/newalias16.go @@ -11,13 +11,18 @@ import ( "go/types" ) -func newAlias(pos token.Pos, pkg *types.Package, name string, orig types.Object) types.Object { - errorf("unexpected alias in non-Go1.8 export data: %s.%s => %v", pkg.Name(), name, orig) +type types_Alias struct { + types.Object + dummy int +} // satisfies types.Object but will never be encountered + +func types_NewAlias(pos token.Pos, pkg *types.Package, name string, orig types.Object) types.Object { + errorf("unexpected alias in non-Go1.8 export data: %s.%s => %v", pkg.Name(), name, orig) // panics panic("unreachable") } -func original(obj types.Object) types.Object { - return obj // don't know about aliases +func original(types.Object) types.Object { + panic("unreachable") } const testfile = "exports17.go" diff --git a/go/gcimporter15/newalias18.go b/go/gcimporter15/newalias18.go index ff4d5354..56740c1c 100644 --- a/go/gcimporter15/newalias18.go +++ b/go/gcimporter15/newalias18.go @@ -8,7 +8,9 @@ package gcimporter import "go/types" -func newAlias => types.NewAlias +type types_Alias => types.Alias + +func types_NewAlias => types.NewAlias // TODO(gri) Consider exporting this functionality from go/types (issue 17730). func original(obj types.Object) types.Object {