internal/gcimporter: port CL 424876 from std importer

This is a port of CL 424876, except it temporarily maintains a
fallback path for older cmd/compile behavior before CL 455279, to
avoid breaking users following Go tip.

Updates golang/go#57015.

Change-Id: I168d171153d96485e92be19645422fe65ab4b345
Reviewed-on: https://go-review.googlesource.com/c/tools/+/456376
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/gcimporter/gcimporter_test.go b/internal/gcimporter/gcimporter_test.go
index ab9a4db..bdae455 100644
--- a/internal/gcimporter/gcimporter_test.go
+++ b/internal/gcimporter/gcimporter_test.go
@@ -796,6 +796,21 @@
 	_ = importPkg(t, "./testdata/aa", tmpdir)
 }
 
+func TestIssue57015(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")
+	}
+
+	compileAndImportPkg(t, "issue57015")
+}
+
 // apkg returns the package "a" prefixed by (as a package) testoutdir
 func apkg(testoutdir string) string {
 	apkg := testoutdir + "/a"
diff --git a/internal/gcimporter/testdata/issue57015.go b/internal/gcimporter/testdata/issue57015.go
new file mode 100644
index 0000000..b6be811
--- /dev/null
+++ b/internal/gcimporter/testdata/issue57015.go
@@ -0,0 +1,16 @@
+// 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 issue57015
+
+type E error
+
+type X[T any] struct {}
+
+func F() X[interface {
+	E
+}] {
+	panic(0)
+}
+
diff --git a/internal/gcimporter/ureader_yes.go b/internal/gcimporter/ureader_yes.go
index 20b9990..b285a11 100644
--- a/internal/gcimporter/ureader_yes.go
+++ b/internal/gcimporter/ureader_yes.go
@@ -559,18 +559,7 @@
 
 			named.SetTypeParams(r.typeParamNames())
 
-			rhs := r.typ()
-			pk := r.p
-			pk.laterFor(named, func() {
-				// First be sure that the rhs is initialized, if it needs to be initialized.
-				delete(pk.laterFors, named) // prevent cycles
-				if i, ok := pk.laterFors[rhs]; ok {
-					f := pk.laterFns[i]
-					pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
-					f()                        // initialize RHS
-				}
-				underlying := rhs.Underlying()
-
+			setUnderlying := func(underlying types.Type) {
 				// If the underlying type is an interface, we need to
 				// duplicate its methods so we can replace the receiver
 				// parameter's type (#49906).
@@ -595,7 +584,31 @@
 				}
 
 				named.SetUnderlying(underlying)
-			})
+			}
+
+			// Since go.dev/cl/455279, we can assume rhs.Underlying() will
+			// always be non-nil. However, to temporarily support users of
+			// older snapshot releases, we continue to fallback to the old
+			// behavior for now.
+			//
+			// TODO(mdempsky): Remove fallback code and simplify after
+			// allowing time for snapshot users to upgrade.
+			rhs := r.typ()
+			if underlying := rhs.Underlying(); underlying != nil {
+				setUnderlying(underlying)
+			} else {
+				pk := r.p
+				pk.laterFor(named, func() {
+					// First be sure that the rhs is initialized, if it needs to be initialized.
+					delete(pk.laterFors, named) // prevent cycles
+					if i, ok := pk.laterFors[rhs]; ok {
+						f := pk.laterFns[i]
+						pk.laterFns[i] = func() {} // function is running now, so replace it with a no-op
+						f()                        // initialize RHS
+					}
+					setUnderlying(rhs.Underlying())
+				})
+			}
 
 			for i, n := 0, r.Len(); i < n; i++ {
 				named.AddMethod(r.method())