go/gcimporter: fix importing of anonymous interfaces

This is a backport of https://go-review.googlesource.com/#/c/41198/.

For golang/go#20046.

Change-Id: I58448c7dcc5e835d5c774e253cb56fec6e154f12
Reviewed-on: https://go-review.googlesource.com/41204
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
diff --git a/go/gcimporter15/bimport.go b/go/gcimporter15/bimport.go
index 3bec19c..369dfb6 100644
--- a/go/gcimporter15/bimport.go
+++ b/go/gcimporter15/bimport.go
@@ -28,9 +28,10 @@
 	version int    // export format version
 
 	// object lists
-	strList       []string         // in order of appearance
-	pkgList       []*types.Package // in order of appearance
-	typList       []types.Type     // in order of appearance
+	strList       []string           // in order of appearance
+	pkgList       []*types.Package   // in order of appearance
+	typList       []types.Type       // in order of appearance
+	interfaceList []*types.Interface // for delayed completion only
 	trackAllTypes bool
 
 	// position encoding
@@ -49,12 +50,13 @@
 // and returns the number of bytes consumed and a reference to the package.
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
-func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, _ *types.Package, err error) {
+func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
 	// catch panics and return them as errors
 	defer func() {
 		if e := recover(); e != nil {
 			// The package (filename) causing the problem is added to this
 			// error by a wrapper in the caller (Import in gcimporter.go).
+			// Return a (possibly nil or incomplete) package unchanged (see #16088).
 			err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e)
 		}
 	}()
@@ -119,7 +121,7 @@
 	p.typList = append(p.typList, predeclared...)
 
 	// read package data
-	pkg := p.pkg()
+	pkg = p.pkg()
 
 	// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
 	objcount := 0
@@ -140,15 +142,9 @@
 	// ignore compiler-specific import data
 
 	// complete interfaces
-	for _, typ := range p.typList {
-		// If we only record named types (!p.trackAllTypes),
-		// we must check the underlying types here. If we
-		// track all types, the Underlying() method call is
-		// not needed.
-		// TODO(gri) Remove if p.trackAllTypes is gone.
-		if it, ok := typ.Underlying().(*types.Interface); ok {
-			it.Complete()
-		}
+	// TODO(gri) re-investigate if we still need to do this in a delayed fashion
+	for _, typ := range p.interfaceList {
+		typ.Complete()
 	}
 
 	// record all referenced packages as imports
@@ -500,6 +496,7 @@
 		}
 
 		t := types.NewInterface(p.methodList(parent), embeddeds)
+		p.interfaceList = append(p.interfaceList, t)
 		if p.trackAllTypes {
 			p.typList[n] = t
 		}
diff --git a/go/gcimporter15/gcimporter_test.go b/go/gcimporter15/gcimporter_test.go
index d63f112..56cdfc0 100644
--- a/go/gcimporter15/gcimporter_test.go
+++ b/go/gcimporter15/gcimporter_test.go
@@ -134,7 +134,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	if outFn := compile(t, "testdata", testfile); outFn != "" {
@@ -168,7 +167,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	const dir = "./testdata/versions"
@@ -232,7 +230,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	dt := maxTime
@@ -263,7 +260,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	for _, test := range importedObjectTests {
@@ -299,13 +295,9 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
-	pkg, err := Import(make(map[string]*types.Package), "strings", ".")
-	if err != nil {
-		t.Fatal(err)
-	}
+	pkg := importPkg(t, "strings")
 
 	scope := pkg.Scope()
 	for _, name := range scope.Names() {
@@ -332,7 +324,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	imports := make(map[string]*types.Package)
@@ -356,7 +347,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -373,10 +363,7 @@
 	}
 
 	// import must succeed (test for issue at hand)
-	pkg, err := Import(make(map[string]*types.Package), "./testdata/b", ".")
-	if err != nil {
-		t.Fatal(err)
-	}
+	pkg := importPkg(t, "./testdata/b")
 
 	// make sure all indirectly imported packages have names
 	for _, imp := range pkg.Imports() {
@@ -392,7 +379,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// import go/internal/gcimporter which imports go/types partially
@@ -415,10 +401,7 @@
 	}
 
 	// look for go/types.Object type
-	obj := goTypesPkg.Scope().Lookup("Object")
-	if obj == nil {
-		t.Fatal("go/types.Object not found")
-	}
+	obj := lookupObj(t, goTypesPkg.Scope(), "Object")
 	typ, ok := obj.Type().(*types.Named)
 	if !ok {
 		t.Fatalf("go/types.Object type is %v; wanted named type", typ)
@@ -442,7 +425,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -481,7 +463,6 @@
 	// This package only handles gc export data.
 	if runtime.Compiler != "gc" {
 		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
-		return
 	}
 
 	// On windows, we have to set the -D option for the compiler to avoid having a drive
@@ -494,8 +475,47 @@
 		defer os.Remove(f)
 	}
 
-	imports := make(map[string]*types.Package)
-	if _, err := Import(imports, "./testdata/issue15920", "."); err != nil {
+	importPkg(t, "./testdata/issue15920")
+}
+
+func TestIssue20046(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+	}
+
+	// On windows, we have to set the -D option for the compiler to avoid having a drive
+	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+	if runtime.GOOS == "windows" {
+		t.Skip("avoid dealing with relative paths/drive letters on windows")
+	}
+
+	if f := compile(t, "testdata", "issue20046.go"); f != "" {
+		defer os.Remove(f)
+	}
+
+	// "./issue20046".V.M must exist
+	pkg := importPkg(t, "./testdata/issue20046")
+	obj := lookupObj(t, pkg.Scope(), "V")
+	if m, index, indirect := types.LookupFieldOrMethod(obj.Type(), false, nil, "M"); m == nil {
+		t.Fatalf("V.M not found (index = %v, indirect = %v)", index, indirect)
+	}
+}
+
+func importPkg(t *testing.T, path string) *types.Package {
+	pkg, err := Import(make(map[string]*types.Package), path, ".")
+	if err != nil {
 		t.Fatal(err)
 	}
+	return pkg
+}
+
+func lookupObj(t *testing.T, scope *types.Scope, name string) types.Object {
+	if obj := scope.Lookup(name); obj != nil {
+		return obj
+	}
+	t.Fatalf("%s not found", name)
+	return nil
 }
diff --git a/go/gcimporter15/testdata/issue20046.go b/go/gcimporter15/testdata/issue20046.go
new file mode 100644
index 0000000..c63ee82
--- /dev/null
+++ b/go/gcimporter15/testdata/issue20046.go
@@ -0,0 +1,9 @@
+// Copyright 2017 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.
+
+package p
+
+var V interface {
+	M()
+}