aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2022-11-21 12:10:12 -0800
committerGopher Robot <gobot@golang.org>2022-11-21 21:08:22 +0000
commitf60c77026bb47db984c5da7e6f0590010e7e1a6f (patch)
treeaf6bf2c817ddf3e53036306d72fe0d9074984cb5 /src
parent840b346c5d24a4a8ab5182b6f0711e3c5e65bafc (diff)
downloadgo-f60c77026bb47db984c5da7e6f0590010e7e1a6f.tar.xz
go/types, types2: report empty type sets in operand descriptions
This leads to better error messages where operations are not permitted because of empty type sets. Fixes #51525. Change-Id: I8d15645e2aff5145e458bdf9aaa4d2bee28d37fa Reviewed-on: https://go-review.googlesource.com/c/go/+/452535 Auto-Submit: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Robert Griesemer <gri@google.com> Reviewed-by: Robert Griesemer <gri@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/types2/operand.go4
-rw-r--r--src/cmd/compile/internal/types2/predicates.go12
-rw-r--r--src/go/types/operand.go4
-rw-r--r--src/go/types/predicates.go12
-rw-r--r--src/internal/types/testdata/fixedbugs/issue51525.go4
5 files changed, 36 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go
index bdbbfc1ecb..e49afee987 100644
--- a/src/cmd/compile/internal/types2/operand.go
+++ b/src/cmd/compile/internal/types2/operand.go
@@ -184,6 +184,10 @@ func operandString(x *operand, qf Qualifier) string {
if tpar, _ := x.typ.(*TypeParam); tpar != nil {
buf.WriteString(" constrained by ")
WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
+ // If we have the type set and it's empty, say so for better error messages.
+ if hasEmptyTypeset(tpar) {
+ buf.WriteString(" with empty type set")
+ }
}
} else {
buf.WriteString(" with invalid type")
diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go
index c4d11dcac4..acc1549084 100644
--- a/src/cmd/compile/internal/types2/predicates.go
+++ b/src/cmd/compile/internal/types2/predicates.go
@@ -96,6 +96,18 @@ func isTypeParam(t Type) bool {
return ok
}
+// hasEmptyTypeset reports whether t is a type parameter with an empty type set.
+// The function does not force the computation of the type set and so is safe to
+// use anywhere, but it may report a false negative if the type set has not been
+// computed yet.
+func hasEmptyTypeset(t Type) bool {
+ if tpar, _ := t.(*TypeParam); tpar != nil && tpar.bound != nil {
+ iface, _ := safeUnderlying(tpar.bound).(*Interface)
+ return iface != nil && iface.tset != nil && iface.tset.IsEmpty()
+ }
+ return false
+}
+
// isGeneric reports whether a type is a generic, uninstantiated type
// (generic signatures are not included).
// TODO(gri) should we include signatures or assert that they are not present?
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index e21a51a77b..819c99e684 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -171,6 +171,10 @@ func operandString(x *operand, qf Qualifier) string {
if tpar, _ := x.typ.(*TypeParam); tpar != nil {
buf.WriteString(" constrained by ")
WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
+ // If we have the type set and it's empty, say so for better error messages.
+ if hasEmptyTypeset(tpar) {
+ buf.WriteString(" with empty type set")
+ }
}
} else {
buf.WriteString(" with invalid type")
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index aaf4dd52fc..e9a0e438d8 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -98,6 +98,18 @@ func isTypeParam(t Type) bool {
return ok
}
+// hasEmptyTypeset reports whether t is a type parameter with an empty type set.
+// The function does not force the computation of the type set and so is safe to
+// use anywhere, but it may report a false negative if the type set has not been
+// computed yet.
+func hasEmptyTypeset(t Type) bool {
+ if tpar, _ := t.(*TypeParam); tpar != nil && tpar.bound != nil {
+ iface, _ := safeUnderlying(tpar.bound).(*Interface)
+ return iface != nil && iface.tset != nil && iface.tset.IsEmpty()
+ }
+ return false
+}
+
// isGeneric reports whether a type is a generic, uninstantiated type
// (generic signatures are not included).
// TODO(gri) should we include signatures or assert that they are not present?
diff --git a/src/internal/types/testdata/fixedbugs/issue51525.go b/src/internal/types/testdata/fixedbugs/issue51525.go
index af1d1e6063..58569056f0 100644
--- a/src/internal/types/testdata/fixedbugs/issue51525.go
+++ b/src/internal/types/testdata/fixedbugs/issue51525.go
@@ -9,6 +9,10 @@ func _[T interface {
string
}](x T) {
_ = x /* ERROR empty type set */ == x
+ _ = x /* ERROR empty type set */ + x
+ <-x /* ERROR empty type set */
+ x <- /* ERROR empty type set */ 0
+ close(x /* ERROR empty type set */)
}
func _[T interface{ int | []byte }](x T) {