mirror of
https://github.com/golang/go
synced 2024-11-20 08:04:42 -07:00
go/importer: handle multiple imports of the same object
Before aliases, and because we chose a simple export format for them, a package may now export the same object more than once if there are multiple exported aliases referring to that object. The go/importer made the assumption this couldn't happen. Adjust it. Fixes #17726. Change-Id: Ibb9fc669a8748200b45ad78934d7453e5a5aad82 Reviewed-on: https://go-review.googlesource.com/32538 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
012fec3821
commit
c3e0dc23fb
@ -207,18 +207,53 @@ 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) {
|
||||
@ -237,8 +272,7 @@ func (p *importer) obj(tag int) {
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil)
|
||||
val := p.value()
|
||||
obj = types.NewConst(pos, pkg, name, typ, val)
|
||||
p.declare(obj)
|
||||
obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
|
||||
|
||||
case typeTag:
|
||||
obj = p.typ(nil).(*types.Named).Obj()
|
||||
@ -247,8 +281,7 @@ func (p *importer) obj(tag int) {
|
||||
pos := p.pos()
|
||||
pkg, name := p.qualifiedName()
|
||||
typ := p.typ(nil)
|
||||
obj = types.NewVar(pos, pkg, name, typ)
|
||||
p.declare(obj)
|
||||
obj = p.declare(types.NewVar(pos, pkg, name, typ))
|
||||
|
||||
case funcTag:
|
||||
pos := p.pos()
|
||||
@ -256,8 +289,7 @@ func (p *importer) obj(tag int) {
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
sig := types.NewSignature(nil, params, result, isddd)
|
||||
obj = types.NewFunc(pos, pkg, name, sig)
|
||||
p.declare(obj)
|
||||
obj = p.declare(types.NewFunc(pos, pkg, name, sig))
|
||||
|
||||
default:
|
||||
errorf("unexpected object tag %d", tag)
|
||||
|
@ -1308,12 +1308,14 @@ package b
|
||||
import (
|
||||
"./testdata/alias"
|
||||
a "./testdata/alias"
|
||||
// "math" // TODO(gri) does not work yet - fix importer (issue #17726)
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
c1 = alias.Pi
|
||||
c2 => a.Pi
|
||||
c1 = alias.Pi1
|
||||
c2 => a.Pi1
|
||||
c3 => a.Pi2
|
||||
c4 => math.Pi
|
||||
)
|
||||
|
||||
var (
|
||||
@ -1331,7 +1333,8 @@ func f1 => alias.Sin
|
||||
func f2 => a.Sin
|
||||
|
||||
func _() {
|
||||
assert(c1 == c2 && c1 == alias.Pi && c2 == a.Pi)
|
||||
assert(c1 == alias.Pi1 && c2 == a.Pi1 && c3 == a.Pi2 && c4 == math.Pi)
|
||||
assert(c2 == c2 && c2 == c3 && c3 == c4)
|
||||
v1 = v2 // must be assignable
|
||||
var _ *t1 = new(t2) // must be assignable
|
||||
var _ t2 = alias.Default
|
||||
|
3
src/go/types/testdata/alias.go
vendored
3
src/go/types/testdata/alias.go
vendored
@ -11,7 +11,8 @@ import (
|
||||
"math"
|
||||
)
|
||||
|
||||
const Pi => math.Pi
|
||||
const Pi1 => math.Pi
|
||||
const Pi2 => math.Pi // cause the same object to be exported multiple times (issue 17726)
|
||||
|
||||
var Default => build.Default
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user