From c90ead97ad7542437079462e0b70ff7b3f8e7811 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 23 Sep 2021 16:53:21 -0700 Subject: [PATCH] cmd/compile/internal/types2: delay union element checks We cannot determine the underlying type right when parsing a union term since it may lead to types that are not yet fully set up. Fixes #46461. Change-Id: I1fcadb1dcef2160be2f088a4a34e99dbab01da67 Reviewed-on: https://go-review.googlesource.com/c/go/+/351969 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- .../types2/testdata/fixedbugs/issue46461.go2 | 9 +++++++++ src/cmd/compile/internal/types2/typeset.go | 8 ++++---- src/cmd/compile/internal/types2/union.go | 20 +++++++++++++------ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 index bfeaf3a966..8bf31090b8 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 @@ -4,8 +4,17 @@ package p +// test case 1 type T[U interface{ M() T[U] }] int type X int func (X) M() T[X] { return 0 } + +// test case 2 +type A[T interface{ A[T] }] interface{} + +// test case 3 +type A2[U interface{ A2[U] }] interface{ M() A2[U] } + +type I interface{ A2[I]; M() A2[I] } diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index ae39f26e4f..c56aa56e2e 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -291,8 +291,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ terms = tset.terms case *TypeParam: // Embedding stand-alone type parameters is not permitted. - // This case is handled during union parsing. - unreachable() + // Union parsing reports a (delayed) error, so we can ignore this entry. + continue default: if typ == Typ[Invalid] { continue @@ -372,8 +372,8 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *_TypeSet terms = computeInterfaceTypeSet(check, pos, u).terms case *TypeParam: // A stand-alone type parameters is not permitted as union term. - // This case is handled during union parsing. - unreachable() + // Union parsing reports a (delayed) error, so we can ignore this entry. + continue default: if t.typ == Typ[Invalid] { continue diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index d4c749a89b..87985dd133 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -54,7 +54,10 @@ func parseUnion(check *Checker, tlist []syntax.Expr) Type { for _, x := range tlist { tilde, typ := parseTilde(check, x) if len(tlist) == 1 && !tilde { - return typ // single type (optimization) + // Single type. Ok to return early because all relevant + // checks have been performed in parseTilde (no need to + // run through term validity check below). + return typ } if len(terms) >= maxTermCount { check.errorf(x, "cannot handle more than %d union terms (implementation limitation)", maxTermCount) @@ -123,11 +126,16 @@ func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) { tilde = true } typ = check.typ(x) - // embedding stand-alone type parameters is not permitted (issue #47127). - if _, ok := under(typ).(*TypeParam); ok { - check.error(x, "cannot embed a type parameter") - typ = Typ[Invalid] - } + // Embedding stand-alone type parameters is not permitted (issue #47127). + // Do this check later because it requires computation of the underlying type (see also issue #46461). + // Note: If an underlying type cannot be a type parameter, the call to + // under() will not be needed and then we don't need to delay this + // check to later and could return Typ[Invalid] instead. + check.later(func() { + if _, ok := under(typ).(*TypeParam); ok { + check.error(x, "cannot embed a type parameter") + } + }) return } -- 2.48.1