go/gcimporter15: backport double-export fix for aliased objects

Backport of https://golang.org/cl/32575.

Change-Id: Ic4b0794ee440b7ac6275f0ef7dacda20de4fdad0
Reviewed-on: https://go-review.googlesource.com/32577
Reviewed-by: Alan Donovan <adonovan@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/gcimporter15/bexport.go b/go/gcimporter15/bexport.go
index 39f6ce3..f7615ba 100644
--- a/go/gcimporter15/bexport.go
+++ b/go/gcimporter15/bexport.go
@@ -63,6 +63,9 @@
 	pkgIndex map[*types.Package]int
 	typIndex map[types.Type]int
 
+	// track objects that we've reexported already
+	reexported map[types.Object]bool
+
 	// position encoding
 	posInfoFormat bool
 	prevFile      string
@@ -81,6 +84,7 @@
 		strIndex:      map[string]int{"": 0}, // empty string is mapped to 0
 		pkgIndex:      make(map[*types.Package]int),
 		typIndex:      make(map[types.Type]int),
+		reexported:    make(map[types.Object]bool),
 		posInfoFormat: true, // TODO(gri) might become a flag, eventually
 	}
 
@@ -178,10 +182,17 @@
 			// 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())
-		obj = orig
+		p.qualifiedName(orig)
+		return
 	}
 
 	switch obj := obj.(type) {
diff --git a/go/gcimporter15/bimport.go b/go/gcimporter15/bimport.go
index 9bd9eb7..8e9a6b2 100644
--- a/go/gcimporter15/bimport.go
+++ b/go/gcimporter15/bimport.go
@@ -225,10 +225,11 @@
 		return funcTag
 	// Aliases are not exported multiple times, thus we should not see them here.
 	default:
-		errorf("unexpected object: %v (%T)", obj, obj)
+		errorf("unexpected object: %v (%T)", obj, obj) // panics
 		panic("unreachable")
 	}
 }
+
 func sameObj(a, b types.Object) bool {
 	// Because unnamed types are not canonicalized, we cannot simply compare types for
 	// (pointer) identity.
@@ -236,7 +237,7 @@
 	return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
 }
 
-func (p *importer) declare(obj types.Object) types.Object {
+func (p *importer) declare(obj types.Object) {
 	pkg := obj.Pkg()
 	if alt := pkg.Scope().Insert(obj); alt != nil {
 		// This can only trigger if we import a (non-type) object a second time.
@@ -244,48 +245,33 @@
 		// 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).
+		// However, aliases require reexporting the original object, so we need
+		// to allow it (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)
+			errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
 		}
-		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()
-		obj = p.declare(types.NewConst(pos, pkg, name, typ, val))
+		p.declare(types.NewConst(pos, pkg, name, typ, val))
 
 	case typeTag:
-		obj = p.typ(nil).(*types.Named).Obj()
+		p.typ(nil)
 
 	case varTag:
 		pos := p.pos()
 		pkg, name := p.qualifiedName()
 		typ := p.typ(nil)
-		obj = p.declare(types.NewVar(pos, pkg, name, typ))
+		p.declare(types.NewVar(pos, pkg, name, typ))
 
 	case funcTag:
 		pos := p.pos()
@@ -293,15 +279,18 @@
 		params, isddd := p.paramList()
 		result, _ := p.paramList()
 		sig := types.NewSignature(nil, params, result, isddd)
-		obj = p.declare(types.NewFunc(pos, pkg, name, sig))
+		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))
 
 	default:
 		errorf("unexpected object tag %d", tag)
 	}
-
-	if aliasName != "" {
-		p.declare(newAlias(aliasPos, p.pkgList[0], aliasName, obj))
-	}
 }
 
 func (p *importer) pos() token.Pos {
@@ -553,7 +542,7 @@
 		return t
 
 	default:
-		errorf("unexpected type tag %d", i)
+		errorf("unexpected type tag %d", i) // panics
 		panic("unreachable")
 	}
 }
@@ -704,7 +693,7 @@
 	case unknownTag:
 		return constant.MakeUnknown()
 	default:
-		errorf("unexpected value tag %d", tag)
+		errorf("unexpected value tag %d", tag) // panics
 		panic("unreachable")
 	}
 }
diff --git a/go/gcimporter15/newalias18.go b/go/gcimporter15/newalias18.go
index 446a038..ff4d535 100644
--- a/go/gcimporter15/newalias18.go
+++ b/go/gcimporter15/newalias18.go
@@ -12,8 +12,8 @@
 
 // TODO(gri) Consider exporting this functionality from go/types (issue 17730).
 func original(obj types.Object) types.Object {
-	if orig, ok := obj.(*types.Alias); ok {
-		return orig
+	if alias, ok := obj.(*types.Alias); ok {
+		return alias.Orig()
 	}
 	return obj
 }