go/internal/gcimporter: guard against infinite recursion with recursive
type parameters

This is a partial port of CL 386335 to x/tools. I have not yet been able
to reproduce the crash in a test.

For golang/go#51219

Change-Id: I262e6a9dba936b18513ee5f11a2a72d4155d3833
Reviewed-on: https://go-review.googlesource.com/c/tools/+/392475
Trust: Robert Findley <rfindley@google.com>
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/iimport.go b/go/internal/gcimporter/iimport.go
index 1a33cd5..84cfb80 100644
--- a/go/internal/gcimporter/iimport.go
+++ b/go/internal/gcimporter/iimport.go
@@ -237,6 +237,15 @@
 		pkg.MarkComplete()
 	}
 
+	// SetConstraint can't be called if the constraint type is not yet complete.
+	// When type params are created in the 'P' case of (*importReader).obj(),
+	// the associated constraint type may not be complete due to recursion.
+	// Therefore, we defer calling SetConstraint there, and call it here instead
+	// after all types are complete.
+	for _, d := range p.later {
+		typeparams.SetTypeParamConstraint(d.t, d.constraint)
+	}
+
 	for _, typ := range p.interfaceList {
 		typ.Complete()
 	}
@@ -244,6 +253,11 @@
 	return pkgs, nil
 }
 
+type setConstraintArgs struct {
+	t          *typeparams.TypeParam
+	constraint types.Type
+}
+
 type iimporter struct {
 	version int
 	ipath   string
@@ -260,6 +274,9 @@
 	fake          fakeFileSet
 	interfaceList []*types.Interface
 
+	// Arguments for calls to SetConstraint that are deferred due to recursive types
+	later []setConstraintArgs
+
 	indent int // for tracing support
 }
 
@@ -458,7 +475,11 @@
 			}
 			typeparams.MarkImplicit(iface)
 		}
-		typeparams.SetTypeParamConstraint(t, constraint)
+		// The constraint type may not be complete, if we
+		// are in the middle of a type recursion involving type
+		// constraints. So, we defer SetConstraint until we have
+		// completely set up all types in ImportData.
+		r.p.later = append(r.p.later, setConstraintArgs{t: t, constraint: constraint})
 
 	case 'V':
 		typ := r.typ()