mirror of
https://github.com/golang/go
synced 2024-11-23 20:50:04 -07:00
go/types, types2: delay "does not satisfy comparable" error until needed
Fixes #49112. Change-Id: I8effbca7bcbb257b18fd4d3d1914fd10d4afaaae Reviewed-on: https://go-review.googlesource.com/c/go/+/372594 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
87b2a54827
commit
a2004de088
@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
return errorf("cannot implement %s (empty type set)", T)
|
||||
}
|
||||
|
||||
// If T is comparable, V must be comparable.
|
||||
// TODO(gri) the error messages could be better, here
|
||||
if Ti.IsComparable() && !Comparable(V) {
|
||||
if Vi != nil && Vi.Empty() {
|
||||
return errorf("empty interface %s does not implement %s", V, T)
|
||||
}
|
||||
return errorf("%s does not implement comparable", V)
|
||||
}
|
||||
|
||||
// V must implement T (methods)
|
||||
// - check only if we have methods
|
||||
// V must implement T's methods, if any.
|
||||
if Ti.NumMethods() > 0 {
|
||||
if m, wrong := check.missingMethod(V, Ti, true); m != nil {
|
||||
// TODO(gri) needs to print updated name to avoid major confusion in error message!
|
||||
@ -220,10 +210,17 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
}
|
||||
}
|
||||
|
||||
// If T is comparable, V must be comparable.
|
||||
// Remember as a pending error and report only if we don't have a more specific error.
|
||||
var pending error
|
||||
if Ti.IsComparable() && !Comparable(V) {
|
||||
pending = errorf("%s does not implement comparable", V)
|
||||
}
|
||||
|
||||
// V must also be in the set of types of T, if any.
|
||||
// Constraints with empty type sets were already excluded above.
|
||||
if !Ti.typeSet().hasTerms() {
|
||||
return nil // nothing to do
|
||||
return pending // nothing to do
|
||||
}
|
||||
|
||||
// If V is itself an interface, each of its possible types must be in the set
|
||||
@ -234,7 +231,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
// TODO(gri) report which type is missing
|
||||
return errorf("%s does not implement %s", V, T)
|
||||
}
|
||||
return nil
|
||||
return pending
|
||||
}
|
||||
|
||||
// Otherwise, V's type must be included in the iface type set.
|
||||
@ -262,5 +259,5 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return pending
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func _() {
|
||||
type T1[P interface{~uint}] struct{}
|
||||
|
||||
func _[P any]() {
|
||||
_ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
|
||||
_ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
|
||||
}
|
||||
|
||||
// This is the original (simplified) program causing the same issue.
|
||||
@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
|
||||
return u.s + 1
|
||||
}
|
||||
|
||||
func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
|
||||
return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
|
||||
func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
|
||||
return T2[U /* ERROR U does not implement Unsigned */ ]{}
|
||||
}
|
||||
|
||||
func _() {
|
||||
|
@ -16,11 +16,11 @@ func _[P comparable,
|
||||
_ = f[P]
|
||||
_ = f[Q]
|
||||
_ = f[func( /* ERROR does not implement comparable */ )]
|
||||
_ = f[R /* ERROR empty interface R does not implement comparable */ ]
|
||||
_ = f[R /* ERROR R does not implement comparable */ ]
|
||||
|
||||
_ = g[int]
|
||||
_ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
_ = g[Q]
|
||||
_ = g[func( /* ERROR does not implement comparable */ )]
|
||||
_ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
_ = g[func( /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ )]
|
||||
_ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
}
|
||||
|
15
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2
vendored
Normal file
15
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
func f[P int](P) {}
|
||||
|
||||
func _() {
|
||||
_ = f[int]
|
||||
_ = f[[ /* ERROR \[\]int does not implement int */ ]int]
|
||||
|
||||
f(0)
|
||||
f( /* ERROR \[\]int does not implement int */ []int{})
|
||||
}
|
@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
return errorf("cannot implement %s (empty type set)", T)
|
||||
}
|
||||
|
||||
// If T is comparable, V must be comparable.
|
||||
// TODO(gri) the error messages could be better, here
|
||||
if Ti.IsComparable() && !Comparable(V) {
|
||||
if Vi != nil && Vi.Empty() {
|
||||
return errorf("empty interface %s does not implement %s", V, T)
|
||||
}
|
||||
return errorf("%s does not implement comparable", V)
|
||||
}
|
||||
|
||||
// V must implement T (methods)
|
||||
// - check only if we have methods
|
||||
// V must implement T's methods, if any.
|
||||
if Ti.NumMethods() > 0 {
|
||||
if m, wrong := check.missingMethod(V, Ti, true); m != nil {
|
||||
// TODO(gri) needs to print updated name to avoid major confusion in error message!
|
||||
@ -221,10 +211,17 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
}
|
||||
}
|
||||
|
||||
// If T is comparable, V must be comparable.
|
||||
// Remember as a pending error and report only if we don't have a more specific error.
|
||||
var pending error
|
||||
if Ti.IsComparable() && !Comparable(V) {
|
||||
pending = errorf("%s does not implement comparable", V)
|
||||
}
|
||||
|
||||
// V must also be in the set of types of T, if any.
|
||||
// Constraints with empty type sets were already excluded above.
|
||||
if !Ti.typeSet().hasTerms() {
|
||||
return nil // nothing to do
|
||||
return pending // nothing to do
|
||||
}
|
||||
|
||||
// If V is itself an interface, each of its possible types must be in the set
|
||||
@ -235,7 +232,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
// TODO(gri) report which type is missing
|
||||
return errorf("%s does not implement %s", V, T)
|
||||
}
|
||||
return nil
|
||||
return pending
|
||||
}
|
||||
|
||||
// Otherwise, V's type must be included in the iface type set.
|
||||
@ -263,5 +260,5 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return pending
|
||||
}
|
||||
|
6
src/go/types/testdata/check/issues.go2
vendored
6
src/go/types/testdata/check/issues.go2
vendored
@ -58,7 +58,7 @@ func _() {
|
||||
type T1[P interface{~uint}] struct{}
|
||||
|
||||
func _[P any]() {
|
||||
_ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
|
||||
_ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
|
||||
}
|
||||
|
||||
// This is the original (simplified) program causing the same issue.
|
||||
@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
|
||||
return u.s + 1
|
||||
}
|
||||
|
||||
func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
|
||||
return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
|
||||
func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
|
||||
return T2[U /* ERROR U does not implement Unsigned */ ]{}
|
||||
}
|
||||
|
||||
func _() {
|
||||
|
@ -16,11 +16,11 @@ func _[P comparable,
|
||||
_ = f[P]
|
||||
_ = f[Q]
|
||||
_ = f[func /* ERROR does not implement comparable */ ()]
|
||||
_ = f[R /* ERROR empty interface R does not implement comparable */ ]
|
||||
_ = f[R /* ERROR R does not implement comparable */ ]
|
||||
|
||||
_ = g[int]
|
||||
_ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
_ = g[Q]
|
||||
_ = g[func /* ERROR does not implement comparable */ ()]
|
||||
_ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
_ = g[func /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ ()]
|
||||
_ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
|
||||
}
|
||||
|
15
src/go/types/testdata/fixedbugs/issue49112.go2
vendored
Normal file
15
src/go/types/testdata/fixedbugs/issue49112.go2
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
func f[P int](P) {}
|
||||
|
||||
func _() {
|
||||
_ = f[int]
|
||||
_ = f[[ /* ERROR \[\]int does not implement int */ ]int]
|
||||
|
||||
f(0)
|
||||
f/* ERROR \[\]int does not implement int */ ([]int{})
|
||||
}
|
Loading…
Reference in New Issue
Block a user