1
0
mirror of https://github.com/golang/go synced 2024-11-17 21:04:43 -07:00

go/types: delay union element checks

This is a clean port of CL 351969 from types2 to go/types
with a minor adjustment for error handling (provide an error
code).

For #46461.

Change-Id: I493dde12d8ccf86aa33f4913ac6e82f2eb459088
Reviewed-on: https://go-review.googlesource.com/c/go/+/351971
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-09-23 17:35:36 -07:00
parent 4dd5f0994f
commit 0f1159bf54
3 changed files with 27 additions and 10 deletions

View File

@ -4,8 +4,17 @@
package p package p
// test case 1
type T[U interface{ M() T[U] }] int type T[U interface{ M() T[U] }] int
type X int type X int
func (X) M() T[X] { return 0 } 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] }

View File

@ -289,8 +289,8 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
terms = tset.terms terms = tset.terms
case *TypeParam: case *TypeParam:
// Embedding stand-alone type parameters is not permitted. // Embedding stand-alone type parameters is not permitted.
// This case is handled during union parsing. // Union parsing reports a (delayed) error, so we can ignore this entry.
unreachable() continue
default: default:
if typ == Typ[Invalid] { if typ == Typ[Invalid] {
continue continue
@ -370,8 +370,8 @@ func computeUnionTypeSet(check *Checker, pos token.Pos, utyp *Union) *_TypeSet {
terms = computeInterfaceTypeSet(check, pos, u).terms terms = computeInterfaceTypeSet(check, pos, u).terms
case *TypeParam: case *TypeParam:
// A stand-alone type parameters is not permitted as union term. // A stand-alone type parameters is not permitted as union term.
// This case is handled during union parsing. // Union parsing reports a (delayed) error, so we can ignore this entry.
unreachable() continue
default: default:
if t.typ == Typ[Invalid] { if t.typ == Typ[Invalid] {
continue continue

View File

@ -57,7 +57,10 @@ func parseUnion(check *Checker, tlist []ast.Expr) Type {
for _, x := range tlist { for _, x := range tlist {
tilde, typ := parseTilde(check, x) tilde, typ := parseTilde(check, x)
if len(tlist) == 1 && !tilde { 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 { if len(terms) >= maxTermCount {
check.errorf(x, _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount) check.errorf(x, _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
@ -126,11 +129,16 @@ func parseTilde(check *Checker, x ast.Expr) (tilde bool, typ Type) {
tilde = true tilde = true
} }
typ = check.typ(x) typ = check.typ(x)
// embedding stand-alone type parameters is not permitted (issue #47127). // 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 { if _, ok := under(typ).(*TypeParam); ok {
check.error(x, _Todo, "cannot embed a type parameter") check.error(x, _Todo, "cannot embed a type parameter")
typ = Typ[Invalid]
} }
})
return return
} }