go/gcimporter15: implement support for importing aliases
- backport of changes made to std lib: https://go-review.googlesource.com/32350/ https://go-review.googlesource.com/32538 - factored out newAlias for non-Go1.8 builds - tested against 1.6, 1.7, 1.8 Change-Id: I538b2d4a0f0c93c517a7aaa3b1562aa3afd154dd Reviewed-on: https://go-review.googlesource.com/32470 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
4549178751
commit
5b3db00587
|
@ -27,7 +27,7 @@ type importer struct {
|
||||||
data []byte
|
data []byte
|
||||||
path string
|
path string
|
||||||
buf []byte // for reading strings
|
buf []byte // for reading strings
|
||||||
version int
|
version int // export format version
|
||||||
|
|
||||||
// object lists
|
// object lists
|
||||||
strList []string // in order of appearance
|
strList []string // in order of appearance
|
||||||
|
@ -106,13 +106,6 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
||||||
// ...
|
// ...
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case 3, 2, 1:
|
case 3, 2, 1:
|
||||||
// Support for Go 1.8 type aliases will be added very
|
|
||||||
// soon (Oct 2016). In the meantime, we make a
|
|
||||||
// best-effort attempt to read v3 export data, failing
|
|
||||||
// if we encounter a type alias. This allows the
|
|
||||||
// automated builders to make progress since
|
|
||||||
// type aliases are not yet used in practice.
|
|
||||||
// TODO(gri): add support for type aliases.
|
|
||||||
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
|
||||||
p.trackAllTypes = p.int() != 0
|
p.trackAllTypes = p.int() != 0
|
||||||
p.posInfoFormat = p.int() != 0
|
p.posInfoFormat = p.int() != 0
|
||||||
|
@ -193,7 +186,7 @@ func (p *importer) pkg() *types.Package {
|
||||||
|
|
||||||
// we should never see an empty package name
|
// we should never see an empty package name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
panic("empty package name in import")
|
errorf("empty package name in import")
|
||||||
}
|
}
|
||||||
|
|
||||||
// an empty path denotes the package we are currently importing;
|
// an empty path denotes the package we are currently importing;
|
||||||
|
@ -218,37 +211,81 @@ func (p *importer) pkg() *types.Package {
|
||||||
return pkg
|
return pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) declare(obj types.Object) {
|
// 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)
|
||||||
|
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) types.Object {
|
||||||
pkg := obj.Pkg()
|
pkg := obj.Pkg()
|
||||||
if alt := pkg.Scope().Insert(obj); alt != nil {
|
if alt := pkg.Scope().Insert(obj); alt != nil {
|
||||||
// This could only trigger if we import a (non-type) object a second time.
|
// This can only trigger if we import a (non-type) object a second time.
|
||||||
// This should never happen because 1) we only import a package once; and
|
// Excluding aliases, this cannot happen because 1) we only import a package
|
||||||
// b) we ignore compiler-specific export data which may contain functions
|
// once; and b) we ignore compiler-specific export data which may contain
|
||||||
// whose inlined function bodies refer to other functions that were already
|
// functions whose inlined function bodies refer to other functions that
|
||||||
// imported.
|
// were already imported.
|
||||||
// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
|
// However, if a package exports multiple aliases referring to the same
|
||||||
// switch case importing functions).
|
// original object, that object is currently exported multiple times.
|
||||||
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)
|
// Check for that specific case and accept it if the aliases correspond
|
||||||
|
// (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.
|
||||||
|
// TODO(gri) We can avoid doing this once objects are exported only once
|
||||||
|
// per package again (issue #17636).
|
||||||
|
if !sameObj(obj, alt) {
|
||||||
|
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)
|
||||||
|
}
|
||||||
|
obj = alt // use object that was imported first
|
||||||
}
|
}
|
||||||
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) obj(tag int) {
|
func (p *importer) obj(tag int) {
|
||||||
|
var aliasPos token.Pos
|
||||||
|
var aliasName string
|
||||||
|
if tag == aliasTag {
|
||||||
|
aliasPos = p.pos()
|
||||||
|
aliasName = p.string()
|
||||||
|
tag = p.tagOrIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj types.Object
|
||||||
switch tag {
|
switch tag {
|
||||||
case constTag:
|
case constTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
pkg, name := p.qualifiedName()
|
pkg, name := p.qualifiedName()
|
||||||
typ := p.typ(nil)
|
typ := p.typ(nil)
|
||||||
val := p.value()
|
val := p.value()
|
||||||
p.declare(types.NewConst(pos, pkg, name, typ, val))
|
obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||||
|
|
||||||
case typeTag:
|
case typeTag:
|
||||||
_ = p.typ(nil)
|
obj = p.typ(nil).(*types.Named).Obj()
|
||||||
|
|
||||||
case varTag:
|
case varTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
pkg, name := p.qualifiedName()
|
pkg, name := p.qualifiedName()
|
||||||
typ := p.typ(nil)
|
typ := p.typ(nil)
|
||||||
p.declare(types.NewVar(pos, pkg, name, typ))
|
obj = p.declare(types.NewVar(pos, pkg, name, typ))
|
||||||
|
|
||||||
case funcTag:
|
case funcTag:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
|
@ -256,11 +293,15 @@ func (p *importer) obj(tag int) {
|
||||||
params, isddd := p.paramList()
|
params, isddd := p.paramList()
|
||||||
result, _ := p.paramList()
|
result, _ := p.paramList()
|
||||||
sig := types.NewSignature(nil, params, result, isddd)
|
sig := types.NewSignature(nil, params, result, isddd)
|
||||||
p.declare(types.NewFunc(pos, pkg, name, sig))
|
obj = p.declare(types.NewFunc(pos, pkg, name, sig))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
errorf("unexpected object tag %d", tag)
|
errorf("unexpected object tag %d", tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if aliasName != "" {
|
||||||
|
p.declare(newAlias(aliasPos, p.pkgList[0], aliasName, obj))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *importer) pos() token.Pos {
|
func (p *importer) pos() token.Pos {
|
||||||
|
@ -469,7 +510,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
|
||||||
|
|
||||||
// no embedded interfaces with gc compiler
|
// no embedded interfaces with gc compiler
|
||||||
if p.int() != 0 {
|
if p.int() != 0 {
|
||||||
panic("unexpected embedded interface")
|
errorf("unexpected embedded interface")
|
||||||
}
|
}
|
||||||
|
|
||||||
t := types.NewInterface(p.methodList(parent), nil)
|
t := types.NewInterface(p.methodList(parent), nil)
|
||||||
|
@ -544,7 +585,7 @@ func (p *importer) field(parent *types.Package) *types.Var {
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
name = typ.Obj().Name()
|
name = typ.Obj().Name()
|
||||||
default:
|
default:
|
||||||
panic("anonymous field expected")
|
errorf("anonymous field expected")
|
||||||
}
|
}
|
||||||
anonymous = true
|
anonymous = true
|
||||||
}
|
}
|
||||||
|
@ -623,7 +664,7 @@ func (p *importer) param(named bool) (*types.Var, bool) {
|
||||||
if named {
|
if named {
|
||||||
name = p.string()
|
name = p.string()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
panic("expected named parameter")
|
errorf("expected named parameter")
|
||||||
}
|
}
|
||||||
if name != "_" {
|
if name != "_" {
|
||||||
pkg = p.pkg()
|
pkg = p.pkg()
|
||||||
|
@ -727,7 +768,7 @@ func (p *importer) tagOrIndex() int {
|
||||||
func (p *importer) int() int {
|
func (p *importer) int() int {
|
||||||
x := p.int64()
|
x := p.int64()
|
||||||
if int64(int(x)) != x {
|
if int64(int(x)) != x {
|
||||||
panic("exported integer too large")
|
errorf("exported integer too large")
|
||||||
}
|
}
|
||||||
return int(x)
|
return int(x)
|
||||||
}
|
}
|
||||||
|
@ -814,7 +855,7 @@ func (p *importer) rawByte() byte {
|
||||||
case '|':
|
case '|':
|
||||||
// nothing to do
|
// nothing to do
|
||||||
default:
|
default:
|
||||||
panic("unexpected escape sequence in export data")
|
errorf("unexpected escape sequence in export data")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.data = p.data[r:]
|
p.data = p.data[r:]
|
||||||
|
@ -856,7 +897,11 @@ const (
|
||||||
fractionTag // not used by gc
|
fractionTag // not used by gc
|
||||||
complexTag
|
complexTag
|
||||||
stringTag
|
stringTag
|
||||||
|
nilTag // only used by gc (appears in exported inlined function bodies)
|
||||||
unknownTag // not used by gc (only appears in packages with errors)
|
unknownTag // not used by gc (only appears in packages with errors)
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
aliasTag
|
||||||
)
|
)
|
||||||
|
|
||||||
var predeclared = []types.Type{
|
var predeclared = []types.Type{
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// 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.6,!go1.8
|
||||||
|
|
||||||
|
package gcimporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/token"
|
||||||
|
"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)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import "go/types"
|
||||||
|
|
||||||
|
func newAlias => types.NewAlias
|
Loading…
Reference in New Issue