}
// Otherwise, V's type must be included in the iface type set.
- if !Ti.typeSet().includes(V) {
- // TODO(gri) report which type is missing
- return errorf("%s does not implement %s", V, T)
+ var alt Type
+ if Ti.typeSet().is(func(t *term) bool {
+ if !t.includes(V) {
+ // If V ∉ t.typ but V ∈ ~t.typ then remember this type
+ // so we can suggest it as an alternative in the error
+ // message.
+ if alt == nil && !t.tilde && Identical(t.typ, under(t.typ)) {
+ tt := *t
+ tt.tilde = true
+ if tt.includes(V) {
+ alt = t.typ
+ }
+ }
+ return true
+ }
+ return false
+ }) {
+ if alt != nil {
+ return errorf("%s does not implement %s (possibly missing ~ for %s in constraint %s)", V, T, alt, T)
+ } else {
+ return errorf("%s does not implement %s", V, T)
+ }
}
return nil
package p
+func f1[P int | string]() {}
+func f2[P ~int | string | float64]() {}
+func f3[P int](x P) {}
+
+type myInt int
+type myFloat float64
+
+func _() {
+ _ = f1[int]
+ _ = f1[myInt /* ERROR possibly missing ~ for int in constraint int\|string */]
+ _ = f2[myInt]
+ _ = f2[myFloat /* ERROR possibly missing ~ for float64 in constraint int\|string|float64 */]
+ var x myInt
+ f3( /* ERROR myInt does not implement int \(possibly missing ~ for int in constraint int\) */ x)
+}
+
+// test case from the issue
+
type SliceConstraint[T any] interface {
[]T
}
type MySlice []int
func f(s MySlice) {
- Map[MySlice /* ERROR MySlice does not implement SliceConstraint\[int\] */, int](s, nil)
+ Map[MySlice /* ERROR MySlice does not implement SliceConstraint\[int\] \(possibly missing ~ for \[\]int in constraint SliceConstraint\[int\]\) */, int](s, nil)
}
func (s *_TypeSet) singleType() Type { return s.terms.singleType() }
// includes reports whether t ∈ s.
+// TODO(gri) This function is not used anywhere anymore. Remove once we
+// are clear that we don't need it elsewhere in the future.
func (s *_TypeSet) includes(t Type) bool { return s.terms.includes(t) }
// subsetOf reports whether s1 ⊆ s2.