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
|
||||
path string
|
||||
buf []byte // for reading strings
|
||||
version int
|
||||
version int // export format version
|
||||
|
||||
// object lists
|
||||
strList []string // in order of appearance
|
||||
|
@ -106,13 +106,6 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
|
|||
// ...
|
||||
// fallthrough
|
||||
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.trackAllTypes = 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
|
||||
if name == "" {
|
||||
panic("empty package name in import")
|
||||
errorf("empty package name in import")
|
||||
}
|
||||
|
||||
// an empty path denotes the package we are currently importing;
|
||||
|
@ -218,37 +211,81 @@ func (p *importer) pkg() *types.Package {
|
|||
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()
|
||||
if alt := pkg.Scope().Insert(obj); alt != nil {
|
||||
// This could 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
|
||||
// b) we ignore compiler-specific export data which may contain functions
|
||||
// whose inlined function bodies refer to other functions that were already
|
||||
// imported.
|
||||
// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
|
||||
// switch case importing functions).
|
||||
errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj)
|
||||
// This can only trigger if we import a (non-type) object a second time.
|
||||
// Excluding aliases, this cannot happen because 1) we only import a package
|
||||
// once; and b) we ignore compiler-specific export data which may contain
|
||||
// functions whose inlined function bodies refer to other functions that
|
||||
// were already imported.
|
||||
// However, if a package exports multiple aliases referring to the same
|
||||
// original object, that object is currently exported multiple times.
|
||||
// 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) {
|
||||
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 {
|
||||
case constTag:
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil)
|
||||
val := p.value()
|
||||
p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||
obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||
|
||||
case typeTag:
|
||||
_ = p.typ(nil)
|
||||
obj = p.typ(nil).(*types.Named).Obj()
|
||||
|
||||
case varTag:
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil)
|
||||
p.declare(types.NewVar(pos, pkg, name, typ))
|
||||
obj = p.declare(types.NewVar(pos, pkg, name, typ))
|
||||
|
||||
case funcTag:
|
||||
pos := p.pos()
|
||||
|
@ -256,11 +293,15 @@ func (p *importer) obj(tag int) {
|
|||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
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:
|
||||
errorf("unexpected object tag %d", tag)
|
||||
}
|
||||
|
||||
if aliasName != "" {
|
||||
p.declare(newAlias(aliasPos, p.pkgList[0], aliasName, obj))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if p.int() != 0 {
|
||||
panic("unexpected embedded interface")
|
||||
errorf("unexpected embedded interface")
|
||||
}
|
||||
|
||||
t := types.NewInterface(p.methodList(parent), nil)
|
||||
|
@ -544,7 +585,7 @@ func (p *importer) field(parent *types.Package) *types.Var {
|
|||
case *types.Named:
|
||||
name = typ.Obj().Name()
|
||||
default:
|
||||
panic("anonymous field expected")
|
||||
errorf("anonymous field expected")
|
||||
}
|
||||
anonymous = true
|
||||
}
|
||||
|
@ -623,7 +664,7 @@ func (p *importer) param(named bool) (*types.Var, bool) {
|
|||
if named {
|
||||
name = p.string()
|
||||
if name == "" {
|
||||
panic("expected named parameter")
|
||||
errorf("expected named parameter")
|
||||
}
|
||||
if name != "_" {
|
||||
pkg = p.pkg()
|
||||
|
@ -727,7 +768,7 @@ func (p *importer) tagOrIndex() int {
|
|||
func (p *importer) int() int {
|
||||
x := p.int64()
|
||||
if int64(int(x)) != x {
|
||||
panic("exported integer too large")
|
||||
errorf("exported integer too large")
|
||||
}
|
||||
return int(x)
|
||||
}
|
||||
|
@ -814,7 +855,7 @@ func (p *importer) rawByte() byte {
|
|||
case '|':
|
||||
// nothing to do
|
||||
default:
|
||||
panic("unexpected escape sequence in export data")
|
||||
errorf("unexpected escape sequence in export data")
|
||||
}
|
||||
}
|
||||
p.data = p.data[r:]
|
||||
|
@ -856,7 +897,11 @@ const (
|
|||
fractionTag // not used by gc
|
||||
complexTag
|
||||
stringTag
|
||||
nilTag // only used by gc (appears in exported inlined function bodies)
|
||||
unknownTag // not used by gc (only appears in packages with errors)
|
||||
|
||||
// Aliases
|
||||
aliasTag
|
||||
)
|
||||
|
||||
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