aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-12-15 21:25:50 -0800
committerRobert Griesemer <gri@golang.org>2022-01-09 18:43:51 +0000
commit2639f2f79bda2c3a4e9ef7381ca7de14935e2a4a (patch)
treee20c12e04f7fb1534eb43492a7d758cef86c51d8 /src
parent90860e0c3110ac5898dfe8e0e0fafd0aea8d979a (diff)
downloadgo-2639f2f79bda2c3a4e9ef7381ca7de14935e2a4a.tar.gz
go-2639f2f79bda2c3a4e9ef7381ca7de14935e2a4a.zip
go/types, types2: better error message for invalid == on type parameters
Fixes #48712. Change-Id: I6f214cdfdd1815493f2a04828e8f0097f1d8c124 Reviewed-on: https://go-review.googlesource.com/c/go/+/372734 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>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/types2/expr.go18
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go241
-rw-r--r--src/go/types/expr.go18
-rw-r--r--src/go/types/testdata/fixedbugs/issue48712.go241
4 files changed, 110 insertions, 8 deletions
diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go
index 3e3104abb6..0147e2adfd 100644
--- a/src/cmd/compile/internal/types2/expr.go
+++ b/src/cmd/compile/internal/types2/expr.go
@@ -770,10 +770,12 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
xok, _ := x.assignableTo(check, y.typ, nil)
yok, _ := y.assignableTo(check, x.typ, nil)
if xok || yok {
+ equality := false
defined := false
switch op {
case syntax.Eql, syntax.Neq:
// spec: "The equality operators == and != apply to operands that are comparable."
+ equality = true
defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
case syntax.Lss, syntax.Leq, syntax.Gtr, syntax.Geq:
// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
@@ -782,11 +784,19 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
unreachable()
}
if !defined {
- typ := x.typ
- if x.isNil() {
- typ = y.typ
+ if equality && (isTypeParam(x.typ) || isTypeParam(y.typ)) {
+ typ := x.typ
+ if isTypeParam(y.typ) {
+ typ = y.typ
+ }
+ err = check.sprintf("%s is not comparable", typ)
+ } else {
+ typ := x.typ
+ if x.isNil() {
+ typ = y.typ
+ }
+ err = check.sprintf("operator %s not defined on %s", op, typ)
}
- err = check.sprintf("operator %s not defined on %s", op, typ)
}
} else {
err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2
new file mode 100644
index 0000000000..bad8712fda
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2
@@ -0,0 +1,41 @@
+// Copyright 2022 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 _[P comparable](x, y P) {
+ _ = x == x
+ _ = x == y
+ _ = y == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P comparable](x P, y any) {
+ _ = x == x
+ _ = x == y
+ _ = y == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P any](x, y P) {
+ _ = x /* ERROR P is not comparable */ == x
+ _ = x /* ERROR P is not comparable */ == y
+ _ = y /* ERROR P is not comparable */ == x
+ _ = y /* ERROR P is not comparable */ == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P any](x P, y any) {
+ _ = x /* ERROR P is not comparable */ == x
+ _ = x /* ERROR P is not comparable */ == y
+ _ = y /* ERROR P is not comparable */ == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 8ddfb8de7e..73b01f4aa4 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -729,10 +729,12 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
xok, _ := x.assignableTo(check, y.typ, nil)
yok, _ := y.assignableTo(check, x.typ, nil)
if xok || yok {
+ equality := false
defined := false
switch op {
case token.EQL, token.NEQ:
// spec: "The equality operators == and != apply to operands that are comparable."
+ equality = true
defined = Comparable(x.typ) && Comparable(y.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
case token.LSS, token.LEQ, token.GTR, token.GEQ:
// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
@@ -741,11 +743,19 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
unreachable()
}
if !defined {
- typ := x.typ
- if x.isNil() {
- typ = y.typ
+ if equality && (isTypeParam(x.typ) || isTypeParam(y.typ)) {
+ typ := x.typ
+ if isTypeParam(y.typ) {
+ typ = y.typ
+ }
+ err = check.sprintf("%s is not comparable", typ)
+ } else {
+ typ := x.typ
+ if x.isNil() {
+ typ = y.typ
+ }
+ err = check.sprintf("operator %s not defined on %s", op, typ)
}
- err = check.sprintf("operator %s not defined on %s", op, typ)
code = _UndefinedOp
}
} else {
diff --git a/src/go/types/testdata/fixedbugs/issue48712.go2 b/src/go/types/testdata/fixedbugs/issue48712.go2
new file mode 100644
index 0000000000..bad8712fda
--- /dev/null
+++ b/src/go/types/testdata/fixedbugs/issue48712.go2
@@ -0,0 +1,41 @@
+// Copyright 2022 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 _[P comparable](x, y P) {
+ _ = x == x
+ _ = x == y
+ _ = y == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P comparable](x P, y any) {
+ _ = x == x
+ _ = x == y
+ _ = y == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P any](x, y P) {
+ _ = x /* ERROR P is not comparable */ == x
+ _ = x /* ERROR P is not comparable */ == y
+ _ = y /* ERROR P is not comparable */ == x
+ _ = y /* ERROR P is not comparable */ == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}
+
+func _[P any](x P, y any) {
+ _ = x /* ERROR P is not comparable */ == x
+ _ = x /* ERROR P is not comparable */ == y
+ _ = y /* ERROR P is not comparable */ == x
+ _ = y == y
+
+ _ = x /* ERROR operator < not defined on P */ < y
+}