diff options
author | Robert Griesemer <gri@golang.org> | 2021-12-15 21:25:50 -0800 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2022-01-09 18:43:51 +0000 |
commit | 2639f2f79bda2c3a4e9ef7381ca7de14935e2a4a (patch) | |
tree | e20c12e04f7fb1534eb43492a7d758cef86c51d8 /src | |
parent | 90860e0c3110ac5898dfe8e0e0fafd0aea8d979a (diff) | |
download | go-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.go | 18 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2 | 41 | ||||
-rw-r--r-- | src/go/types/expr.go | 18 | ||||
-rw-r--r-- | src/go/types/testdata/fixedbugs/issue48712.go2 | 41 |
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 +} |