From 2ea9376266b71e8a0752b8b3663bbf5b9ed48c4d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 30 Mar 2022 12:19:24 -0700 Subject: [PATCH] go/types, types2: better error message for invalid type parameter term The spec says "In a union, a term cannot be a type parameter,...", but it's really the type in a term that cannot be a type parameter. (Also, for the spec's purposes, a single term is still a union.) This CL changes the current error message from: "cannot use type parameter in typeset" to one of two messages: "term cannot be a type parameter" (for term of form P) "type in term ~P cannot be a type parameter (for term of form ~P) which are more specific and match the spec more closely. Fixes #50420. Change-Id: Id48503efc8416cabc03d5c40d8e64d5b3a7f078e Reviewed-on: https://go-review.googlesource.com/c/go/+/396874 Trust: Robert Griesemer Reviewed-by: Ian Lance Taylor --- .../types2/testdata/examples/constraints.go | 6 ++-- .../types2/testdata/fixedbugs/issue39948.go | 2 +- .../types2/testdata/fixedbugs/issue47127.go | 32 +++++++++---------- src/cmd/compile/internal/types2/union.go | 6 +++- src/go/types/testdata/examples/constraints.go | 6 ++-- src/go/types/testdata/fixedbugs/issue39948.go | 2 +- src/go/types/testdata/fixedbugs/issue47127.go | 32 +++++++++---------- src/go/types/union.go | 6 +++- 8 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go b/src/cmd/compile/internal/types2/testdata/examples/constraints.go index 4d7f70313a..fb01be56a2 100644 --- a/src/cmd/compile/internal/types2/testdata/examples/constraints.go +++ b/src/cmd/compile/internal/types2/testdata/examples/constraints.go @@ -44,9 +44,9 @@ type ( type ( _[T interface{ *T } ] struct{} // ok _[T interface{ int | *T } ] struct{} // ok - _[T interface{ T /* ERROR cannot embed a type parameter */ } ] struct{} - _[T interface{ ~T /* ERROR cannot embed a type parameter */ } ] struct{} - _[T interface{ int|T /* ERROR cannot embed a type parameter */ }] struct{} + _[T interface{ T /* ERROR term cannot be a type parameter */ } ] struct{} + _[T interface{ ~T /* ERROR type in term ~T cannot be a type parameter */ } ] struct{} + _[T interface{ int|T /* ERROR term cannot be a type parameter */ }] struct{} ) // Multiple embedded union elements are intersected. The order in which they diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go index e38e57268d..c893cc049e 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go @@ -5,5 +5,5 @@ package p type T[P any] interface{ - P // ERROR cannot embed a type parameter + P // ERROR term cannot be a type parameter } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go index 108d600a38..bb4b487eb2 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go @@ -8,30 +8,30 @@ package p type ( _[P any] interface{ *P | []P | chan P | map[string]P } - _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _[P any] interface{ int | P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } ) func _[P any]() { type ( _[P any] interface{ *P | []P | chan P | map[string]P } - _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _[P any] interface{ int | P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } _ interface{ *P | []P | chan P | map[string]P } - _ interface{ P /* ERROR "cannot embed a type parameter" */ } - _ interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _ interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _ interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _ interface{ P /* ERROR term cannot be a type parameter */ } + _ interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _ interface{ int | P /* ERROR term cannot be a type parameter */ } + _ interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } ) } func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() {} -func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() {} +func _[P any, Q interface{ P /* ERROR term cannot be a type parameter */ }]() {} +func _[P any, Q interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ }]() {} +func _[P any, Q interface{ int | P /* ERROR term cannot be a type parameter */ }]() {} +func _[P any, Q interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ }]() {} diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 132e73098a..57f1a4fe2a 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -148,7 +148,11 @@ func parseTilde(check *Checker, tx syntax.Expr) *Term { // simply use its underlying type (like we do for other named, embedded interfaces), // and since the underlying type is an interface the embedding is well defined. if isTypeParam(typ) { - check.error(x, "cannot embed a type parameter") + if tilde { + check.errorf(x, "type in term %s cannot be a type parameter", tx) + } else { + check.error(x, "term cannot be a type parameter") + } typ = Typ[Invalid] } term := NewTerm(tilde, typ) diff --git a/src/go/types/testdata/examples/constraints.go b/src/go/types/testdata/examples/constraints.go index 4d7f70313a..fb01be56a2 100644 --- a/src/go/types/testdata/examples/constraints.go +++ b/src/go/types/testdata/examples/constraints.go @@ -44,9 +44,9 @@ type ( type ( _[T interface{ *T } ] struct{} // ok _[T interface{ int | *T } ] struct{} // ok - _[T interface{ T /* ERROR cannot embed a type parameter */ } ] struct{} - _[T interface{ ~T /* ERROR cannot embed a type parameter */ } ] struct{} - _[T interface{ int|T /* ERROR cannot embed a type parameter */ }] struct{} + _[T interface{ T /* ERROR term cannot be a type parameter */ } ] struct{} + _[T interface{ ~T /* ERROR type in term ~T cannot be a type parameter */ } ] struct{} + _[T interface{ int|T /* ERROR term cannot be a type parameter */ }] struct{} ) // Multiple embedded union elements are intersected. The order in which they diff --git a/src/go/types/testdata/fixedbugs/issue39948.go b/src/go/types/testdata/fixedbugs/issue39948.go index e38e57268d..c893cc049e 100644 --- a/src/go/types/testdata/fixedbugs/issue39948.go +++ b/src/go/types/testdata/fixedbugs/issue39948.go @@ -5,5 +5,5 @@ package p type T[P any] interface{ - P // ERROR cannot embed a type parameter + P // ERROR term cannot be a type parameter } diff --git a/src/go/types/testdata/fixedbugs/issue47127.go b/src/go/types/testdata/fixedbugs/issue47127.go index 108d600a38..bb4b487eb2 100644 --- a/src/go/types/testdata/fixedbugs/issue47127.go +++ b/src/go/types/testdata/fixedbugs/issue47127.go @@ -8,30 +8,30 @@ package p type ( _[P any] interface{ *P | []P | chan P | map[string]P } - _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _[P any] interface{ int | P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } ) func _[P any]() { type ( _[P any] interface{ *P | []P | chan P | map[string]P } - _[P any] interface{ P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _[P any] interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _[P any] interface{ P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _[P any] interface{ int | P /* ERROR term cannot be a type parameter */ } + _[P any] interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } _ interface{ *P | []P | chan P | map[string]P } - _ interface{ P /* ERROR "cannot embed a type parameter" */ } - _ interface{ ~P /* ERROR "cannot embed a type parameter" */ } - _ interface{ int | P /* ERROR "cannot embed a type parameter" */ } - _ interface{ int | ~P /* ERROR "cannot embed a type parameter" */ } + _ interface{ P /* ERROR term cannot be a type parameter */ } + _ interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ } + _ interface{ int | P /* ERROR term cannot be a type parameter */ } + _ interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ } ) } func _[P any, Q interface{ *P | []P | chan P | map[string]P }]() {} -func _[P any, Q interface{ P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ ~P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ int | P /* ERROR "cannot embed a type parameter" */ }]() {} -func _[P any, Q interface{ int | ~P /* ERROR "cannot embed a type parameter" */ }]() {} +func _[P any, Q interface{ P /* ERROR term cannot be a type parameter */ }]() {} +func _[P any, Q interface{ ~P /* ERROR type in term ~P cannot be a type parameter */ }]() {} +func _[P any, Q interface{ int | P /* ERROR term cannot be a type parameter */ }]() {} +func _[P any, Q interface{ int | ~P /* ERROR type in term ~P cannot be a type parameter */ }]() {} diff --git a/src/go/types/union.go b/src/go/types/union.go index 1a8825fcab..b288dfab5c 100644 --- a/src/go/types/union.go +++ b/src/go/types/union.go @@ -151,7 +151,11 @@ func parseTilde(check *Checker, tx ast.Expr) *Term { // simply use its underlying type (like we do for other named, embedded interfaces), // and since the underlying type is an interface the embedding is well defined. if isTypeParam(typ) { - check.error(x, _MisplacedTypeParam, "cannot embed a type parameter") + if tilde { + check.errorf(x, _MisplacedTypeParam, "type in term %s cannot be a type parameter", tx) + } else { + check.error(x, _MisplacedTypeParam, "term cannot be a type parameter") + } typ = Typ[Invalid] } term := NewTerm(tilde, typ)