1
0
mirror of https://github.com/golang/go synced 2024-11-19 00:44:40 -07:00

go.tools/go/types: test cases for comparisons

- better error messages
- in contrast to a long-standing TODO, comparisons
  between interface and non-interface types always
  worked correctly

R=adonovan
CC=golang-dev
https://golang.org/cl/17310043
This commit is contained in:
Robert Griesemer 2013-10-25 13:16:45 -07:00
parent d644aa1fcd
commit cf08eefe7f
6 changed files with 248 additions and 18 deletions

View File

@ -188,5 +188,3 @@ func Implements(V Type, T *Interface, static bool) bool {
f, _ := MissingMethod(V, T, static) f, _ := MissingMethod(V, T, static)
return f == nil return f == nil
} }
// BUG(gri): Interface vs non-interface comparisons are not correctly implemented.

View File

@ -24,7 +24,7 @@ func unreachable() {
panic("unreachable") panic("unreachable")
} }
func (check *checker) formatMsg(format string, args []interface{}) string { func (check *checker) sprintf(format string, args ...interface{}) string {
for i, arg := range args { for i, arg := range args {
switch a := arg.(type) { switch a := arg.(type) {
case nil: case nil:
@ -44,13 +44,13 @@ func (check *checker) trace(pos token.Pos, format string, args ...interface{}) {
fmt.Printf("%s:\t%s%s\n", fmt.Printf("%s:\t%s%s\n",
check.fset.Position(pos), check.fset.Position(pos),
strings.Repeat(". ", check.indent), strings.Repeat(". ", check.indent),
check.formatMsg(format, args), check.sprintf(format, args...),
) )
} }
// dump is only needed for debugging // dump is only needed for debugging
func (check *checker) dump(format string, args ...interface{}) { func (check *checker) dump(format string, args ...interface{}) {
fmt.Println(check.formatMsg(format, args)) fmt.Println(check.sprintf(format, args...))
} }
func (check *checker) err(err error) { func (check *checker) err(err error) {
@ -65,7 +65,7 @@ func (check *checker) err(err error) {
} }
func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) { func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) {
check.err(fmt.Errorf("%s: %s", check.fset.Position(pos), check.formatMsg(format, args))) check.err(fmt.Errorf("%s: %s", check.fset.Position(pos), check.sprintf(format, args...)))
} }
func (check *checker) invalidAST(pos token.Pos, format string, args ...interface{}) { func (check *checker) invalidAST(pos token.Pos, format string, args ...interface{}) {

View File

@ -560,24 +560,34 @@ Error:
} }
func (check *checker) comparison(x, y *operand, op token.Token) { func (check *checker) comparison(x, y *operand, op token.Token) {
// TODO(gri) deal with interface vs non-interface comparison // spec: "In any comparison, the first operand must be assignable
// to the type of the second operand, or vice versa."
valid := false err := ""
if x.isAssignableTo(check.conf, y.typ) || y.isAssignableTo(check.conf, x.typ) { if x.isAssignableTo(check.conf, y.typ) || y.isAssignableTo(check.conf, x.typ) {
defined := false
switch op { switch op {
case token.EQL, token.NEQ: case token.EQL, token.NEQ:
valid = isComparable(x.typ) || // spec: "The equality operators == and != apply to operands that are comparable."
x.isNil() && hasNil(y.typ) || defined = isComparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
y.isNil() && hasNil(x.typ)
case token.LSS, token.LEQ, token.GTR, token.GEQ: case token.LSS, token.LEQ, token.GTR, token.GEQ:
valid = isOrdered(x.typ) // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
defined = isOrdered(x.typ)
default: default:
unreachable() unreachable()
} }
if !defined {
typ := x.typ
if x.isNil() {
typ = y.typ
}
err = check.sprintf("operator %s not defined for %s", op, typ)
}
} else {
err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
} }
if !valid { if err != "" {
check.invalidOp(x.pos(), "cannot compare %s %s %s", x, op, y) check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
x.mode = invalid x.mode = invalid
return return
} }

View File

@ -81,7 +81,6 @@ func isComparable(typ Type) bool {
case *Basic: case *Basic:
return t.kind != Invalid && t.kind != UntypedNil return t.kind != Invalid && t.kind != UntypedNil
case *Pointer, *Interface, *Chan: case *Pointer, *Interface, *Chan:
// assumes types are equal for pointers and channels
return true return true
case *Struct: case *Struct:
for _, f := range t.fields { for _, f := range t.fields {

View File

@ -100,7 +100,7 @@ const (
tb0 bool = false tb0 bool = false
tb1 bool = true tb1 bool = true
tb2 mybool = 2 < 1 tb2 mybool = 2 < 1
tb3 mybool = ti1 /* ERROR "cannot compare" */ == tf1 tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
// integer values // integer values
ti0 int8 = ui0 ti0 int8 = ui0

View File

@ -21,4 +21,227 @@ func _bool() {
// corner cases // corner cases
var ( var (
v0 = nil /* ERROR "cannot compare" */ == nil v0 = nil /* ERROR "cannot compare" */ == nil
) )
func arrays() {
// basics
var a, b [10]int
_ = a == b
_ = a != b
_ = a /* ERROR < not defined */ < b
_ = a == nil /* ERROR cannot convert */
type C [10]int
var c C
_ = a == c
type D [10]int
var d D
_ = c /* ERROR mismatched types */ == d
var e [10]func() int
_ = e /* ERROR == not defined */ == e
}
func structs() {
// basics
var s, t struct {
x int
a [10]float32
_ bool
}
_ = s == t
_ = s != t
_ = s /* ERROR < not defined */ < t
_ = s == nil /* ERROR cannot convert */
type S struct {
x int
a [10]float32
_ bool
}
type T struct {
x int
a [10]float32
_ bool
}
var ss S
var tt T
_ = s == ss
_ = ss /* ERROR mismatched types */ == tt
var u struct {
x int
a [10]map[string]int
}
_ = u /* ERROR cannot compare */ == u
}
func pointers() {
// nil
_ = nil /* ERROR == not defined */ == nil
_ = nil /* ERROR != not defined */ != nil
_ = nil /* ERROR < not defined */ < nil
_ = nil /* ERROR <= not defined */ <= nil
_ = nil /* ERROR > not defined */ > nil
_ = nil /* ERROR >= not defined */ >= nil
// basics
var p, q *int
_ = p == q
_ = p != q
_ = p == nil
_ = p != nil
_ = nil == q
_ = nil != q
_ = p /* ERROR < not defined */ < q
_ = p /* ERROR <= not defined */ <= q
_ = p /* ERROR > not defined */ > q
_ = p /* ERROR >= not defined */ >= q
// various element types
type (
S1 struct{}
S2 struct{}
P1 *S1
P2 *S2
)
var (
ps1 *S1
ps2 *S2
p1 P1
p2 P2
)
_ = ps1 == ps1
_ = ps1 /* ERROR mismatched types */ == ps2
_ = ps2 /* ERROR mismatched types */ == ps1
_ = p1 == p1
_ = p1 /* ERROR mismatched types */ == p2
_ = p1 == ps1
}
func channels() {
// basics
var c, d chan int
_ = c == d
_ = c != d
_ = c == nil
_ = c /* ERROR < not defined */ < d
// various element types (named types)
type (
C1 chan int
C1r <-chan int
C1s chan<- int
C2 chan float32
)
var (
c1 C1
c1r C1r
c1s C1s
c1a chan int
c2 C2
)
_ = c1 == c1
_ = c1 /* ERROR mismatched types */ == c1r
_ = c1 /* ERROR mismatched types */ == c1s
_ = c1r /* ERROR mismatched types */ == c1s
_ = c1 == c1a
_ = c1a == c1
_ = c1 /* ERROR mismatched types */ == c2
_ = c1a /* ERROR mismatched types */ == c2
// various element types (unnamed types)
var (
d1 chan int
d1r <-chan int
d1s chan<- int
d1a chan<- int
d2 chan float32
)
_ = d1 == d1
_ = d1 == d1r
_ = d1 == d1s
_ = d1r /* ERROR mismatched types */ == d1s
_ = d1 == d1a
_ = d1a == d1
_ = d1 /* ERROR mismatched types */ == d2
_ = d1a /* ERROR mismatched types */ == d2
}
// for interfaces test
type S1 struct{}
type S11 struct{}
type S2 struct{}
func (*S1) m() int
func (*S11) m() int
func (*S11) n()
func (*S2) m() float32
func interfaces() {
// basics
var i, j interface{ m() int }
_ = i == j
_ = i != j
_ = i == nil
_ = i /* ERROR < not defined */ < j
// various interfaces
var ii interface { m() int; n() }
var k interface { m() float32 }
_ = i == ii
_ = i /* ERROR mismatched types */ == k
// interfaces vs values
var s1 S1
var s11 S11
var s2 S2
_ = i == 0 /* ERROR cannot convert */
_ = i /* ERROR mismatched types */ == s1
_ = i == &s1
_ = i == &s11
_ = i /* ERROR mismatched types */ == s2
_ = i /* ERROR mismatched types */ == &s2
}
func slices() {
// basics
var s []int
_ = s == nil
_ = s != nil
_ = s /* ERROR < not defined */ < nil
// slices are not otherwise comparable
_ = s /* ERROR == not defined */ == s
_ = s /* ERROR < not defined */ < s
}
func maps() {
// basics
var m map[string]int
_ = m == nil
_ = m != nil
_ = m /* ERROR < not defined */ < nil
// maps are not otherwise comparable
_ = m /* ERROR == not defined */ == m
_ = m /* ERROR < not defined */ < m
}
func funcs() {
// basics
var f func(int) float32
_ = f == nil
_ = f != nil
_ = f /* ERROR < not defined */ < nil
// funcs are not otherwise comparable
_ = f /* ERROR == not defined */ == f
_ = f /* ERROR < not defined */ < f
}