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()