go/internal/gcimporter: key tparams by Package instead of pkgname

This is a port of CL 394219 to x/tools. A test is added to reproduce the
failure mode using the x/tools gcimporter.

Updates #51836

Change-Id: I521d4947b084fe9dae08de96450568e0dd5399b0
Reviewed-on: https://go-review.googlesource.com/c/tools/+/400815
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/go/internal/gcimporter/gcimporter_test.go b/go/internal/gcimporter/gcimporter_test.go
index 6baab01..4e992af 100644
--- a/go/internal/gcimporter/gcimporter_test.go
+++ b/go/internal/gcimporter/gcimporter_test.go
@@ -587,6 +587,37 @@
 	compileAndImportPkg(t, "issue25301")
 }
 
+func TestIssue51836(t *testing.T) {
+	testenv.NeedsGo1Point(t, 18) // requires generics
+
+	// This package only handles gc export data.
+	needsCompiler(t, "gc")
+
+	// 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")
+	}
+
+	tmpdir := mktmpdir(t)
+	defer os.RemoveAll(tmpdir)
+	testoutdir := filepath.Join(tmpdir, "testdata")
+
+	dir := filepath.Join("testdata", "issue51836")
+	// Following the pattern of TestIssue13898, aa.go needs to be compiled from
+	// the output directory. We pass the full path to compile() so that we don't
+	// have to copy the file to that directory.
+	bpath, err := filepath.Abs(filepath.Join(dir, "aa.go"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	compile(t, dir, "a.go", testoutdir)
+	compile(t, testoutdir, bpath, testoutdir)
+
+	// import must succeed (test for issue at hand)
+	_ = importPkg(t, "./testdata/aa", tmpdir)
+}
+
 func importPkg(t *testing.T, path, srcDir string) *types.Package {
 	pkg, err := Import(make(map[string]*types.Package), path, srcDir, nil)
 	if err != nil {
diff --git a/go/internal/gcimporter/iimport.go b/go/internal/gcimporter/iimport.go
index 1d5650a..28b91b8 100644
--- a/go/internal/gcimporter/iimport.go
+++ b/go/internal/gcimporter/iimport.go
@@ -53,7 +53,7 @@
 )
 
 type ident struct {
-	pkg  string
+	pkg  *types.Package
 	name string
 }
 
@@ -463,7 +463,7 @@
 
 		// To handle recursive references to the typeparam within its
 		// bound, save the partial type in tparamIndex before reading the bounds.
-		id := ident{r.currPkg.Name(), name}
+		id := ident{r.currPkg, name}
 		r.p.tparamIndex[id] = t
 		var implicit bool
 		if r.p.version >= iexportVersionGo1_18 {
@@ -779,7 +779,7 @@
 			errorf("unexpected type param type")
 		}
 		pkg, name := r.qualifiedIdent()
-		id := ident{pkg.Name(), name}
+		id := ident{pkg, name}
 		if t, ok := r.p.tparamIndex[id]; ok {
 			// We're already in the process of importing this typeparam.
 			return t
diff --git a/go/internal/gcimporter/testdata/issue51836/a.go b/go/internal/gcimporter/testdata/issue51836/a.go
new file mode 100644
index 0000000..e9223c9
--- /dev/null
+++ b/go/internal/gcimporter/testdata/issue51836/a.go
@@ -0,0 +1,8 @@
+// Copyright 2022 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 a
+
+type T[K any] struct {
+}
diff --git a/go/internal/gcimporter/testdata/issue51836/aa.go b/go/internal/gcimporter/testdata/issue51836/aa.go
new file mode 100644
index 0000000..d774be2
--- /dev/null
+++ b/go/internal/gcimporter/testdata/issue51836/aa.go
@@ -0,0 +1,13 @@
+// Copyright 2022 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 a
+
+import (
+	"./a"
+)
+
+type T[K any] struct {
+	t a.T[K]
+}