]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: report empty type sets in operand descriptions
authorRobert Griesemer <gri@golang.org>
Mon, 21 Nov 2022 20:10:12 +0000 (12:10 -0800)
committerGopher Robot <gobot@golang.org>
Mon, 21 Nov 2022 21:08:22 +0000 (21:08 +0000)
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>
src/cmd/compile/internal/types2/operand.go
src/cmd/compile/internal/types2/predicates.go
src/go/types/operand.go
src/go/types/predicates.go
src/internal/types/testdata/fixedbugs/issue51525.go

index bdbbfc1ecbec1bcd322d7e4ecea7c0d1dda55701..e49afee987e0ad7b198b589eb2b0aed65ea72031 100644 (file)
@@ -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")
index c4d11dcac4b12c088bc9d56b8ed17e9bf206b303..acc15490846a9ca7c15bb1cc4247d2baf5cf251d 100644 (file)
@@ -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?
index e21a51a77b84ecdb66354141e0b53a31d006cd46..819c99e684cc5ba23d0674f00d8583733e0332b0 100644 (file)
@@ -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")
index aaf4dd52fc5228686cccdf8944d2cf5ba89a9a2b..e9a0e438d888afcb2ff1294a5d7ec0bf08bb6894 100644 (file)
@@ -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?
index af1d1e6063d0a0bab02dca7e1da2081666e54887..58569056f0844a5589d70a06fc28c519caaed387 100644 (file)
@@ -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) {