]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: delay union element checks
authorRobert Griesemer <gri@golang.org>
Thu, 23 Sep 2021 23:53:21 +0000 (16:53 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 24 Sep 2021 00:30:36 +0000 (00:30 +0000)
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 <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2
src/cmd/compile/internal/types2/typeset.go
src/cmd/compile/internal/types2/union.go

index bfeaf3a96689adf35ab04861ad98df7f9e729001..8bf31090b8b5e76be7b8549fe6732cdf55fef3d1 100644 (file)
@@ -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] }
index ae39f26e4f54319bc6b429bf0057f8dc88bc63f5..c56aa56e2ea09eadcd61ff0e15c594bb1e379f31 100644 (file)
@@ -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
index d4c749a89b9e956a0964e91196990c5c82df2fbb..87985dd13355804ec7f6939897800d73a8dcb049 100644 (file)
@@ -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
 }