go/internal/gcimporter, gccgoimporter: updated to match latest version in std lib

This CL brings over the changes from:

https://go-review.googlesource.com/118496 (better error message when importer is out of date)
https://go-review.googlesource.com/114317 (permit embedding of non-defined interfaces via alias type names)
https://go-review.googlesource.com/85318  (use named receiver types for methods of named interfaces)
https://go-review.googlesource.com/42870  (report import path if package is not found)
https://go-review.googlesource.com/41710  (version tests for 1.8, v4 and v5)

Also updated go/gcexportdata to select between binary and new indexed export format.

For golang/go#25856.
For golang/go#25301.
For golang/go#20230.
For golang/go#13829.

Change-Id: Ibf77c50f86e767cef411bd1d3809e12397678958
Reviewed-on: https://go-review.googlesource.com/118555
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/go/gcexportdata/gcexportdata.go b/go/gcexportdata/gcexportdata.go
index 997d3b2..4c238d1 100644
--- a/go/gcexportdata/gcexportdata.go
+++ b/go/gcexportdata/gcexportdata.go
@@ -85,6 +85,14 @@
 		return gcimporter.ImportData(imports, path, path, bytes.NewReader(data))
 	}
 
+	// The indexed export format starts with an 'i'; the older
+	// binary export format starts with a 'c', 'd', or 'v'
+	// (from "version"). Select appropriate importer.
+	if len(data) > 0 && data[0] == 'i' {
+		_, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path)
+		return pkg, err
+	}
+
 	_, pkg, err := gcimporter.BImportData(fset, imports, data, path)
 	return pkg, err
 }
diff --git a/go/internal/gccgoimporter/parser.go b/go/internal/gccgoimporter/parser.go
index 9e20df0..8d00cba 100644
--- a/go/internal/gccgoimporter/parser.go
+++ b/go/internal/gccgoimporter/parser.go
@@ -587,13 +587,13 @@
 	p.expectKeyword("interface")
 
 	var methods []*types.Func
-	var typs []*types.Named
+	var embeddeds []types.Type
 
 	p.expect('{')
 	for p.tok != '}' && p.tok != scanner.EOF {
 		if p.tok == '?' {
 			p.next()
-			typs = append(typs, p.parseType(pkg).(*types.Named))
+			embeddeds = append(embeddeds, p.parseType(pkg))
 		} else {
 			method := p.parseFunc(pkg)
 			methods = append(methods, method)
@@ -602,7 +602,7 @@
 	}
 	p.expect('}')
 
-	return types.NewInterface(methods, typs)
+	return types.NewInterface2(methods, embeddeds)
 }
 
 // PointerType = "*" ("any" | Type) .
diff --git a/go/internal/gcimporter/bexport.go b/go/internal/gcimporter/bexport.go
index b106172..6a9821a 100644
--- a/go/internal/gcimporter/bexport.go
+++ b/go/internal/gcimporter/bexport.go
@@ -38,6 +38,11 @@
 const trace = false // default: false
 
 // Current export format version. Increase with each format change.
+// Note: The latest binary (non-indexed) export format is at version 6.
+//       This exporter is still at level 4, but it doesn't matter since
+//       the binary importer can handle older versions just fine.
+// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE
+// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMEMTED HERE
 // 4: type name objects support type aliases, uses aliasTag
 // 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
 // 2: removed unused bool in ODCL export (compiler only)
diff --git a/go/internal/gcimporter/bimport.go b/go/internal/gcimporter/bimport.go
index 3e845ea..6d98457 100644
--- a/go/internal/gcimporter/bimport.go
+++ b/go/internal/gcimporter/bimport.go
@@ -52,24 +52,24 @@
 // compromised, an error is returned.
 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
+	const currentVersion = 6
+	version := -1 // unknown version
 	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)
+			if version > currentVersion {
+				err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
+			} else {
+				err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
+			}
 		}
 	}()
 
-	if len(data) > 0 && data[0] == 'i' {
-		return iImportData(fset, imports, data[1:], path)
-	}
-
 	p := importer{
 		imports:    imports,
 		data:       data,
 		importpath: path,
-		version:    -1,           // unknown version
+		version:    version,
 		strList:    []string{""}, // empty string is mapped to 0
 		pathList:   []string{""}, // empty string is mapped to 0
 		fake: fakeFileSet{
@@ -94,7 +94,7 @@
 		p.posInfoFormat = p.int() != 0
 		versionstr = p.string()
 		if versionstr == "v1" {
-			p.version = 0
+			version = 0
 		}
 	} else {
 		// Go1.8 extensible encoding
@@ -102,24 +102,25 @@
 		versionstr = p.rawStringln(b)
 		if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
 			if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
-				p.version = v
+				version = v
 			}
 		}
 	}
+	p.version = version
 
 	// read version specific flags - extend as necessary
 	switch p.version {
-	// case 7:
+	// case currentVersion:
 	// 	...
 	//	fallthrough
-	case 6, 5, 4, 3, 2, 1:
+	case currentVersion, 5, 4, 3, 2, 1:
 		p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
 		p.trackAllTypes = p.int() != 0
 		p.posInfoFormat = p.int() != 0
 	case 0:
 		// Go1.7 encoding format - nothing to do here
 	default:
-		errorf("unknown export format version %d (%q)", p.version, versionstr)
+		errorf("unknown bexport format version %d (%q)", p.version, versionstr)
 	}
 
 	// --- generic export data ---
@@ -531,13 +532,13 @@
 			p.record(nil)
 		}
 
-		var embeddeds []*types.Named
+		var embeddeds []types.Type
 		for n := p.int(); n > 0; n-- {
 			p.pos()
-			embeddeds = append(embeddeds, p.typ(parent, nil).(*types.Named))
+			embeddeds = append(embeddeds, p.typ(parent, nil))
 		}
 
-		t := types.NewInterface(p.methodList(parent, tname), embeddeds)
+		t := types.NewInterface2(p.methodList(parent, tname), embeddeds)
 		p.interfaceList = append(p.interfaceList, t)
 		if p.trackAllTypes {
 			p.typList[n] = t
diff --git a/go/internal/gcimporter/gcimporter.go b/go/internal/gcimporter/gcimporter.go
index 58e558c..12408e0 100644
--- a/go/internal/gcimporter/gcimporter.go
+++ b/go/internal/gcimporter/gcimporter.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file is a copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go,
+// This file is a modified copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go,
 // but it also contains the original source-based importer code for Go1.6.
 // Once we stop supporting 1.6, we can remove that code.
 
@@ -55,6 +55,7 @@
 		}
 		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
 		if bp.PkgObj == "" {
+			id = path // make sure we have an id to print in error message
 			return
 		}
 		noext = strings.TrimSuffix(bp.PkgObj, ".a")
@@ -133,7 +134,7 @@
 		if path == "unsafe" {
 			return types.Unsafe, nil
 		}
-		err = fmt.Errorf("can't find import: %s", id)
+		err = fmt.Errorf("can't find import: %q", id)
 		return
 	}
 
@@ -164,14 +165,27 @@
 	switch hdr {
 	case "$$\n":
 		return ImportData(packages, filename, id, buf)
+
 	case "$$B\n":
 		var data []byte
 		data, err = ioutil.ReadAll(buf)
-		if err == nil {
-			fset := token.NewFileSet()
-			_, pkg, err = BImportData(fset, packages, data, id)
-			return
+		if err != nil {
+			break
 		}
+
+		// TODO(gri): allow clients of go/importer to provide a FileSet.
+		// Or, define a new standard go/types/gcexportdata package.
+		fset := token.NewFileSet()
+
+		// The indexed export format starts with an 'i'; the older
+		// binary export format starts with a 'c', 'd', or 'v'
+		// (from "version"). Select appropriate importer.
+		if len(data) > 0 && data[0] == 'i' {
+			_, pkg, err = IImportData(fset, packages, data[1:], id)
+		} else {
+			_, pkg, err = BImportData(fset, packages, data, id)
+		}
+
 	default:
 		err = fmt.Errorf("unknown export data header: %q", hdr)
 	}
diff --git a/go/internal/gcimporter/gcimporter_test.go b/go/internal/gcimporter/gcimporter_test.go
index 56cdfc0..07506bd 100644
--- a/go/internal/gcimporter/gcimporter_test.go
+++ b/go/internal/gcimporter/gcimporter_test.go
@@ -185,9 +185,21 @@
 		}
 		pkgpath := "./" + name[:len(name)-2]
 
+		if testing.Verbose() {
+			t.Logf("importing %s", name)
+		}
+
 		// test that export data can be imported
 		_, err := Import(make(map[string]*types.Package), pkgpath, dir)
 		if err != nil {
+			// ok to fail if it fails with a newer version error for select files
+			if strings.Contains(err.Error(), "newer version") {
+				switch name {
+				case "test_go1.11_999b.a", "test_go1.11_999i.a":
+					continue
+				}
+				// fall through
+			}
 			t.Errorf("import %q failed: %v", pkgpath, err)
 			continue
 		}
@@ -251,7 +263,8 @@
 	// TODO(gri) enable again once we're off 1.7 and 1.8.
 	// {"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
 	{"math.Sin", "func Sin(x float64) float64"},
-	// TODO(gri) add more tests
+	// TODO(gri) Add additional tests which are now present in the
+	//           corresponding std library version of this file.
 }
 
 func TestImportedTypes(t *testing.T) {
@@ -286,9 +299,48 @@
 		if got != test.want {
 			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
 		}
+
+		if named, _ := obj.Type().(*types.Named); named != nil {
+			verifyInterfaceMethodRecvs(t, named, 0)
+		}
 	}
 }
 
+// verifyInterfaceMethodRecvs verifies that method receiver types
+// are named if the methods belong to a named interface type.
+func verifyInterfaceMethodRecvs(t *testing.T, named *types.Named, level int) {
+	// avoid endless recursion in case of an embedding bug that lead to a cycle
+	if level > 10 {
+		t.Errorf("%s: embeds itself", named)
+		return
+	}
+
+	iface, _ := named.Underlying().(*types.Interface)
+	if iface == nil {
+		return // not an interface
+	}
+
+	// check explicitly declared methods
+	for i := 0; i < iface.NumExplicitMethods(); i++ {
+		m := iface.ExplicitMethod(i)
+		recv := m.Type().(*types.Signature).Recv()
+		if recv == nil {
+			t.Errorf("%s: missing receiver type", m)
+			continue
+		}
+		if recv.Type() != named {
+			t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
+		}
+	}
+
+	// check embedded interfaces (if they are named, too)
+	for i := 0; i < iface.NumEmbeddeds(); i++ {
+		// embedding of interfaces cannot have cycles; recursion will terminate
+		if etype, _ := iface.EmbeddedType(i).(*types.Named); etype != nil {
+			verifyInterfaceMethodRecvs(t, etype, level+1)
+		}
+	}
+}
 func TestIssue5815(t *testing.T) {
 	skipSpecialPlatforms(t)
 
@@ -504,6 +556,27 @@
 	}
 }
 
+func TestIssue25301(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", "issue25301.go"); f != "" {
+		defer os.Remove(f)
+	}
+
+	importPkg(t, "./testdata/issue25301")
+}
+
 func importPkg(t *testing.T, path string) *types.Package {
 	pkg, err := Import(make(map[string]*types.Package), path, ".")
 	if err != nil {
diff --git a/go/internal/gcimporter/iimport.go b/go/internal/gcimporter/iimport.go
index dfc00a3..8cd357c 100644
--- a/go/internal/gcimporter/iimport.go
+++ b/go/internal/gcimporter/iimport.go
@@ -12,6 +12,7 @@
 import (
 	"bytes"
 	"encoding/binary"
+	"fmt"
 	"go/constant"
 	"go/token"
 	"go/types"
@@ -57,18 +58,30 @@
 	interfaceType
 )
 
-// iImportData imports a package from the serialized package data
+// IImportData imports a package from the serialized package data
 // 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 iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
+func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
+	const currentVersion = 0
+	version := -1
+	defer func() {
+		if e := recover(); e != nil {
+			if version > currentVersion {
+				err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
+			} else {
+				err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
+			}
+		}
+	}()
+
 	r := &intReader{bytes.NewReader(data), path}
 
-	version := r.uint64()
+	version = int(r.uint64())
 	switch version {
-	case 0:
+	case currentVersion:
 	default:
-		errorf("cannot import %q: unknown iexport format version %d", path, version)
+		errorf("unknown iexport format version %d", version)
 	}
 
 	sLen := int64(r.uint64())
@@ -502,10 +515,10 @@
 	case interfaceType:
 		r.currPkg = r.pkg()
 
-		embeddeds := make([]*types.Named, r.uint64())
+		embeddeds := make([]types.Type, r.uint64())
 		for i := range embeddeds {
 			_ = r.pos()
-			embeddeds[i] = r.typ().(*types.Named)
+			embeddeds[i] = r.typ()
 		}
 
 		methods := make([]*types.Func, r.uint64())
@@ -524,7 +537,7 @@
 			methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
 		}
 
-		typ := types.NewInterface(methods, embeddeds)
+		typ := types.NewInterface2(methods, embeddeds)
 		r.p.interfaceList = append(r.p.interfaceList, typ)
 		return typ
 	}
diff --git a/go/internal/gcimporter/testdata/issue25301.go b/go/internal/gcimporter/testdata/issue25301.go
new file mode 100644
index 0000000..e3dc98b
--- /dev/null
+++ b/go/internal/gcimporter/testdata/issue25301.go
@@ -0,0 +1,17 @@
+// Copyright 2018 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 issue25301
+
+type (
+	A = interface {
+		M()
+	}
+	T interface {
+		A
+	}
+	S struct{}
+)
+
+func (S) M() { println("m") }
diff --git a/go/internal/gcimporter/testdata/versions/test.go b/go/internal/gcimporter/testdata/versions/test.go
index ac9c968..6362adc 100644
--- a/go/internal/gcimporter/testdata/versions/test.go
+++ b/go/internal/gcimporter/testdata/versions/test.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This file is a copy of $GOROOT/src/go/internal/gcimporter/testdata/versions.test.go.
+
 // To create a test case for a new export format version,
 // build this package with the latest compiler and store
 // the resulting .a file appropriately named in the versions
@@ -11,7 +13,10 @@
 //
 // go build -o test_go1.$X_$Y.a test.go
 //
-// with $X = Go version and $Y = export format version.
+// with $X = Go version and $Y = export format version
+// (add 'b' or 'i' to distinguish between binary and
+// indexed format starting with 1.11 as long as both
+// formats are supported).
 //
 // Make sure this source is extended such that it exercises
 // whatever export format change has taken place.
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a b/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a
new file mode 100644
index 0000000..b00fefe
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a
Binary files differ
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a b/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a
new file mode 100644
index 0000000..c0a211e
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a
Binary files differ
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a b/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a
new file mode 100644
index 0000000..c35d22d
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a
Binary files differ
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a b/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a
new file mode 100644
index 0000000..99401d7
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a
Binary files differ
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.8_4.a b/go/internal/gcimporter/testdata/versions/test_go1.8_4.a
new file mode 100644
index 0000000..26b8531
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.8_4.a
Binary files differ
diff --git a/go/internal/gcimporter/testdata/versions/test_go1.8_5.a b/go/internal/gcimporter/testdata/versions/test_go1.8_5.a
new file mode 100644
index 0000000..60e52ef
--- /dev/null
+++ b/go/internal/gcimporter/testdata/versions/test_go1.8_5.a
Binary files differ