aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2023-01-03 17:05:53 -0800
committerHeschi Kreinick <heschi@google.com>2023-01-11 17:10:19 +0000
commit6ad27161f8d1b9c5e03fb3415977e1d3c3b11323 (patch)
tree19a17f05f45caab4ba2164e3b489ed96422a8575
parent76d39ae3499238ac7efb731f4f4cd47b1b3288ab (diff)
downloadgo-6ad27161f8d1b9c5e03fb3415977e1d3c3b11323.tar.gz
go-6ad27161f8d1b9c5e03fb3415977e1d3c3b11323.zip
cmd/compile: better error message for when a type is in a constraint but not the type set
While at it, also remove the word "constraint" in the detail explanation of an unsatisfied constraint. Fixes #57500. Change-Id: I55dae1694de2cfdb434aeba9d4a3530af7aca8f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/460455 Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Run-TryBot: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@google.com>
-rw-r--r--src/cmd/compile/internal/types2/instantiate.go37
-rw-r--r--src/go/types/instantiate.go37
-rw-r--r--src/internal/types/testdata/fixedbugs/issue40350.go2
-rw-r--r--src/internal/types/testdata/fixedbugs/issue49179.go8
-rw-r--r--src/internal/types/testdata/fixedbugs/issue57486.go2
-rw-r--r--src/internal/types/testdata/fixedbugs/issue57500.go16
6 files changed, 88 insertions, 14 deletions
diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go
index f028161118..8193682993 100644
--- a/src/cmd/compile/internal/types2/instantiate.go
+++ b/src/cmd/compile/internal/types2/instantiate.go
@@ -324,14 +324,43 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
return false
}) {
if cause != nil {
- if alt != nil {
- *cause = check.sprintf("%s does not %s %s (possibly missing ~ for %s in constraint %s)", V, verb, T, alt, T)
- } else {
- *cause = check.sprintf("%s does not %s %s (%s missing in %s)", V, verb, T, V, Ti.typeSet().terms)
+ var detail string
+ switch {
+ case alt != nil:
+ detail = check.sprintf("possibly missing ~ for %s in %s", alt, T)
+ case mentions(Ti, V):
+ detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T)
+ default:
+ detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms)
}
+ *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
}
return false
}
return checkComparability()
}
+
+// mentions reports whether type T "mentions" typ in an (embedded) element or term
+// of T (whether typ is in the type set of T or not). For better error messages.
+func mentions(T, typ Type) bool {
+ switch T := T.(type) {
+ case *Interface:
+ for _, e := range T.embeddeds {
+ if mentions(e, typ) {
+ return true
+ }
+ }
+ case *Union:
+ for _, t := range T.terms {
+ if mentions(t.typ, typ) {
+ return true
+ }
+ }
+ default:
+ if Identical(T, typ) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go
index 9f565c326b..2cf48c17d2 100644
--- a/src/go/types/instantiate.go
+++ b/src/go/types/instantiate.go
@@ -324,14 +324,43 @@ func (check *Checker) implements(V, T Type, constraint bool, cause *string) bool
return false
}) {
if cause != nil {
- if alt != nil {
- *cause = check.sprintf("%s does not %s %s (possibly missing ~ for %s in constraint %s)", V, verb, T, alt, T)
- } else {
- *cause = check.sprintf("%s does not %s %s (%s missing in %s)", V, verb, T, V, Ti.typeSet().terms)
+ var detail string
+ switch {
+ case alt != nil:
+ detail = check.sprintf("possibly missing ~ for %s in %s", alt, T)
+ case mentions(Ti, V):
+ detail = check.sprintf("%s mentions %s, but %s is not in the type set of %s", T, V, V, T)
+ default:
+ detail = check.sprintf("%s missing in %s", V, Ti.typeSet().terms)
}
+ *cause = check.sprintf("%s does not %s %s (%s)", V, verb, T, detail)
}
return false
}
return checkComparability()
}
+
+// mentions reports whether type T "mentions" typ in an (embedded) element or term
+// of T (whether typ is in the type set of T or not). For better error messages.
+func mentions(T, typ Type) bool {
+ switch T := T.(type) {
+ case *Interface:
+ for _, e := range T.embeddeds {
+ if mentions(e, typ) {
+ return true
+ }
+ }
+ case *Union:
+ for _, t := range T.terms {
+ if mentions(t.typ, typ) {
+ return true
+ }
+ }
+ default:
+ if Identical(T, typ) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/internal/types/testdata/fixedbugs/issue40350.go b/src/internal/types/testdata/fixedbugs/issue40350.go
index 96ad1678d4..08eb426410 100644
--- a/src/internal/types/testdata/fixedbugs/issue40350.go
+++ b/src/internal/types/testdata/fixedbugs/issue40350.go
@@ -12,5 +12,5 @@ type number interface {
func f[T number]() {}
func _() {
- _ = f[int /* ERROR int does not satisfy number \(int missing in float64 \| ~int32\)*/]
+ _ = f[int /* ERROR int does not satisfy number \(number mentions int, but int is not in the type set of number\)*/]
}
diff --git a/src/internal/types/testdata/fixedbugs/issue49179.go b/src/internal/types/testdata/fixedbugs/issue49179.go
index 468d83edbe..2ddfa3312d 100644
--- a/src/internal/types/testdata/fixedbugs/issue49179.go
+++ b/src/internal/types/testdata/fixedbugs/issue49179.go
@@ -13,11 +13,11 @@ type myFloat float64
func _() {
_ = f1[int]
- _ = f1[myInt /* ERROR possibly missing ~ for int in constraint int \| string */]
+ _ = f1[myInt /* ERROR possibly missing ~ for int in int \| string */]
_ = f2[myInt]
- _ = f2[myFloat /* ERROR possibly missing ~ for float64 in constraint ~int \| string \| float64 */]
+ _ = f2[myFloat /* ERROR possibly missing ~ for float64 in ~int \| string \| float64 */]
var x myInt
- f3 /* ERROR myInt does not satisfy int \(possibly missing ~ for int in constraint int\) */ (x)
+ f3 /* ERROR myInt does not satisfy int \(possibly missing ~ for int in int\) */ (x)
}
// test case from the issue
@@ -33,5 +33,5 @@ func Map[S SliceConstraint[E], E any](s S, f func(E) E) S {
type MySlice []int
func f(s MySlice) {
- Map[MySlice /* ERROR MySlice does not satisfy SliceConstraint\[int\] \(possibly missing ~ for \[\]int in constraint SliceConstraint\[int\]\) */, int](s, nil)
+ Map[MySlice /* ERROR MySlice does not satisfy SliceConstraint\[int\] \(possibly missing ~ for \[\]int in SliceConstraint\[int\]\) */, int](s, nil)
}
diff --git a/src/internal/types/testdata/fixedbugs/issue57486.go b/src/internal/types/testdata/fixedbugs/issue57486.go
index f6ba1b60b8..43ba1b0440 100644
--- a/src/internal/types/testdata/fixedbugs/issue57486.go
+++ b/src/internal/types/testdata/fixedbugs/issue57486.go
@@ -24,6 +24,6 @@ func F1[V [2]any](v V) {
func F2[V [2]any](v V) {
_ = G2[V /* ERROR "V does not satisfy C2" */]
- _ = G2[[ /* ERROR "\[2\]any does not satisfy C2 \(\[2\]any missing in int\)" */ 2]any]
+ _ = G2[[ /* ERROR "\[2\]any does not satisfy C2 \(C2 mentions \[2\]any, but \[2\]any is not in the type set of C2\)" */ 2]any]
_ = G2[int]
}
diff --git a/src/internal/types/testdata/fixedbugs/issue57500.go b/src/internal/types/testdata/fixedbugs/issue57500.go
new file mode 100644
index 0000000000..abdcb5ea35
--- /dev/null
+++ b/src/internal/types/testdata/fixedbugs/issue57500.go
@@ -0,0 +1,16 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type C interface {
+ comparable
+ [2]any | int
+}
+
+func f[T C]() {}
+
+func _() {
+ _ = f[[ /* ERROR \[2\]any does not satisfy C \(C mentions \[2\]any, but \[2\]any is not in the type set of C\) */ 2]any]
+}