Skip to content

Commit a2004de

Browse files
griesemerfindleyr
authored andcommitted
go/types, types2: delay "does not satisfy comparable" error until needed
Fixes golang#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>
1 parent 87b2a54 commit a2004de

File tree

8 files changed

+64
-40
lines changed

8 files changed

+64
-40
lines changed

src/cmd/compile/internal/types2/instantiate.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
192192
return errorf("cannot implement %s (empty type set)", T)
193193
}
194194

195-
// If T is comparable, V must be comparable.
196-
// TODO(gri) the error messages could be better, here
197-
if Ti.IsComparable() && !Comparable(V) {
198-
if Vi != nil && Vi.Empty() {
199-
return errorf("empty interface %s does not implement %s", V, T)
200-
}
201-
return errorf("%s does not implement comparable", V)
202-
}
203-
204-
// V must implement T (methods)
205-
// - check only if we have methods
195+
// V must implement T's methods, if any.
206196
if Ti.NumMethods() > 0 {
207197
if m, wrong := check.missingMethod(V, Ti, true); m != nil {
208198
// 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 {
220210
}
221211
}
222212

213+
// If T is comparable, V must be comparable.
214+
// Remember as a pending error and report only if we don't have a more specific error.
215+
var pending error
216+
if Ti.IsComparable() && !Comparable(V) {
217+
pending = errorf("%s does not implement comparable", V)
218+
}
219+
223220
// V must also be in the set of types of T, if any.
224221
// Constraints with empty type sets were already excluded above.
225222
if !Ti.typeSet().hasTerms() {
226-
return nil // nothing to do
223+
return pending // nothing to do
227224
}
228225

229226
// 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 {
234231
// TODO(gri) report which type is missing
235232
return errorf("%s does not implement %s", V, T)
236233
}
237-
return nil
234+
return pending
238235
}
239236

240237
// 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 {
262259
}
263260
}
264261

265-
return nil
262+
return pending
266263
}

src/cmd/compile/internal/types2/testdata/check/issues.go2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func _() {
5858
type T1[P interface{~uint}] struct{}
5959

6060
func _[P any]() {
61-
_ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
61+
_ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
6262
}
6363

6464
// This is the original (simplified) program causing the same issue.
@@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
7474
return u.s + 1
7575
}
7676

77-
func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
78-
return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
77+
func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
78+
return T2[U /* ERROR U does not implement Unsigned */ ]{}
7979
}
8080

8181
func _() {

src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ func _[P comparable,
1616
_ = f[P]
1717
_ = f[Q]
1818
_ = f[func( /* ERROR does not implement comparable */ )]
19-
_ = f[R /* ERROR empty interface R does not implement comparable */ ]
19+
_ = f[R /* ERROR R does not implement comparable */ ]
2020

2121
_ = g[int]
2222
_ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
2323
_ = g[Q]
24-
_ = g[func( /* ERROR does not implement comparable */ )]
25-
_ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
24+
_ = g[func( /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ )]
25+
_ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
2626
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
func f[P int](P) {}
8+
9+
func _() {
10+
_ = f[int]
11+
_ = f[[ /* ERROR \[\]int does not implement int */ ]int]
12+
13+
f(0)
14+
f( /* ERROR \[\]int does not implement int */ []int{})
15+
}

src/go/types/instantiate.go

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
192192
return errorf("cannot implement %s (empty type set)", T)
193193
}
194194

195-
// If T is comparable, V must be comparable.
196-
// TODO(gri) the error messages could be better, here
197-
if Ti.IsComparable() && !Comparable(V) {
198-
if Vi != nil && Vi.Empty() {
199-
return errorf("empty interface %s does not implement %s", V, T)
200-
}
201-
return errorf("%s does not implement comparable", V)
202-
}
203-
204-
// V must implement T (methods)
205-
// - check only if we have methods
195+
// V must implement T's methods, if any.
206196
if Ti.NumMethods() > 0 {
207197
if m, wrong := check.missingMethod(V, Ti, true); m != nil {
208198
// 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 {
221211
}
222212
}
223213

214+
// If T is comparable, V must be comparable.
215+
// Remember as a pending error and report only if we don't have a more specific error.
216+
var pending error
217+
if Ti.IsComparable() && !Comparable(V) {
218+
pending = errorf("%s does not implement comparable", V)
219+
}
220+
224221
// V must also be in the set of types of T, if any.
225222
// Constraints with empty type sets were already excluded above.
226223
if !Ti.typeSet().hasTerms() {
227-
return nil // nothing to do
224+
return pending // nothing to do
228225
}
229226

230227
// 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 {
235232
// TODO(gri) report which type is missing
236233
return errorf("%s does not implement %s", V, T)
237234
}
238-
return nil
235+
return pending
239236
}
240237

241238
// 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 {
263260
}
264261
}
265262

266-
return nil
263+
return pending
267264
}

src/go/types/testdata/check/issues.go2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func _() {
5858
type T1[P interface{~uint}] struct{}
5959

6060
func _[P any]() {
61-
_ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
61+
_ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
6262
}
6363

6464
// This is the original (simplified) program causing the same issue.
@@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
7474
return u.s + 1
7575
}
7676

77-
func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
78-
return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
77+
func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
78+
return T2[U /* ERROR U does not implement Unsigned */ ]{}
7979
}
8080

8181
func _() {

src/go/types/testdata/fixedbugs/issue47411.go2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ func _[P comparable,
1616
_ = f[P]
1717
_ = f[Q]
1818
_ = f[func /* ERROR does not implement comparable */ ()]
19-
_ = f[R /* ERROR empty interface R does not implement comparable */ ]
19+
_ = f[R /* ERROR R does not implement comparable */ ]
2020

2121
_ = g[int]
2222
_ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
2323
_ = g[Q]
24-
_ = g[func /* ERROR does not implement comparable */ ()]
25-
_ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
24+
_ = g[func /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ ()]
25+
_ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
2626
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package p
6+
7+
func f[P int](P) {}
8+
9+
func _() {
10+
_ = f[int]
11+
_ = f[[ /* ERROR \[\]int does not implement int */ ]int]
12+
13+
f(0)
14+
f/* ERROR \[\]int does not implement int */ ([]int{})
15+
}

0 commit comments

Comments
 (0)