]> Cypherpunks repositories - gostls13.git/commitdiff
go/importer: handle multiple imports of the same object
authorRobert Griesemer <gri@golang.org>
Tue, 1 Nov 2016 21:46:59 +0000 (14:46 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 1 Nov 2016 22:32:45 +0000 (22:32 +0000)
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>

src/go/internal/gcimporter/bimport.go
src/go/types/api_test.go
src/go/types/testdata/alias.go

index 2d6133a31b7905c0150737dbf6ac96e8651f8b0a..9e2fbd3c684a83272faaba008a60f8a62519cd50 100644 (file)
@@ -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)
index 4db9760ba5927d20e487122280698fa12f27e45c..17a98f91a87fc41f79fd1fcc121f3eae5598dccc 100644 (file)
@@ -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
index c74aeaa48ed159de464f74b53a2fab148596e154..40111fb060a5e3af576aaa390ff19d3ac3ec574c 100644 (file)
@@ -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