mirror of
https://github.com/golang/go
synced 2024-11-21 19:24:45 -07:00
gc: implement new comparison rule
The new comparison rule was added to the spec by changeset: 5605:33abb649cb63 user: Robert Griesemer <gri@golang.org> date: Thu Jun 03 16:55:50 2010 -0700 files: doc/go_spec.html description: go spec: Base comparison compatibility on assignment compatibility. Specifically: - Simplified definition of comparison compatibility and folded into section on comparison operators since it's only used there. This is a small language change/cleanup. As a consequence: - An interface value may now be compared against a non-interface value. - Channels with opposite directions cannot be compared directly anymore (per discussion with rsc). R=rsc, r, iant, ken2 CC=golang-dev https://golang.org/cl/1462041 but never implemented. Fixes #1070. R=ken2 CC=golang-dev https://golang.org/cl/2116047
This commit is contained in:
parent
c3900387db
commit
23bd214aee
@ -63,7 +63,7 @@ typechecklist(NodeList *l, int top)
|
|||||||
Node*
|
Node*
|
||||||
typecheck(Node **np, int top)
|
typecheck(Node **np, int top)
|
||||||
{
|
{
|
||||||
int et, op, ptr;
|
int et, aop, op, ptr;
|
||||||
Node *n, *l, *r;
|
Node *n, *l, *r;
|
||||||
NodeList *args;
|
NodeList *args;
|
||||||
int lno, ok, ntop;
|
int lno, ok, ntop;
|
||||||
@ -350,6 +350,26 @@ reswitch:
|
|||||||
et = t->etype;
|
et = t->etype;
|
||||||
if(et == TIDEAL)
|
if(et == TIDEAL)
|
||||||
et = TINT;
|
et = TINT;
|
||||||
|
if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
|
||||||
|
// comparison is okay as long as one side is
|
||||||
|
// assignable to the other. convert so they have
|
||||||
|
// the same type. (the only conversion that isn't
|
||||||
|
// a no-op is concrete == interface.)
|
||||||
|
if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
|
||||||
|
l = nod(aop, l, N);
|
||||||
|
l->type = r->type;
|
||||||
|
l->typecheck = 1;
|
||||||
|
n->left = l;
|
||||||
|
t = l->type;
|
||||||
|
} else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
|
||||||
|
r = nod(aop, r, N);
|
||||||
|
r->type = l->type;
|
||||||
|
r->typecheck = 1;
|
||||||
|
n->right = r;
|
||||||
|
t = r->type;
|
||||||
|
}
|
||||||
|
et = t->etype;
|
||||||
|
}
|
||||||
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
|
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
|
||||||
badbinary:
|
badbinary:
|
||||||
defaultlit2(&l, &r, 1);
|
defaultlit2(&l, &r, 1);
|
||||||
|
54
test/cmp1.go
54
test/cmp1.go
@ -26,6 +26,8 @@ func istrue(b bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type T *int
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var a []int
|
var a []int
|
||||||
var b map[string]int
|
var b map[string]int
|
||||||
@ -55,6 +57,24 @@ func main() {
|
|||||||
isfalse(ib == id)
|
isfalse(ib == id)
|
||||||
istrue(ic == id)
|
istrue(ic == id)
|
||||||
istrue(ie == ie)
|
istrue(ie == ie)
|
||||||
|
|
||||||
|
// these are okay because one side of the
|
||||||
|
// comparison need only be assignable to the other.
|
||||||
|
isfalse(a == ib)
|
||||||
|
isfalse(a == ic)
|
||||||
|
isfalse(a == id)
|
||||||
|
isfalse(b == ic)
|
||||||
|
isfalse(b == id)
|
||||||
|
istrue(c == id)
|
||||||
|
istrue(e == ie)
|
||||||
|
|
||||||
|
isfalse(ia == b)
|
||||||
|
isfalse(ia == c)
|
||||||
|
isfalse(ia == d)
|
||||||
|
isfalse(ib == c)
|
||||||
|
isfalse(ib == d)
|
||||||
|
istrue(ic == d)
|
||||||
|
istrue(ie == e)
|
||||||
|
|
||||||
// 6g used to let this go through as true.
|
// 6g used to let this go through as true.
|
||||||
var g uint64 = 123
|
var g uint64 = 123
|
||||||
@ -73,4 +93,38 @@ func main() {
|
|||||||
println("m[ic] = ", m[ic])
|
println("m[ic] = ", m[ic])
|
||||||
panic("bad m[ic]")
|
panic("bad m[ic]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// non-interface comparisons
|
||||||
|
{
|
||||||
|
c := make(chan int)
|
||||||
|
c1 := (<-chan int)(c)
|
||||||
|
c2 := (chan<- int)(c)
|
||||||
|
istrue(c == c1)
|
||||||
|
istrue(c == c2)
|
||||||
|
istrue(c1 == c)
|
||||||
|
istrue(c2 == c)
|
||||||
|
|
||||||
|
d := make(chan int)
|
||||||
|
isfalse(c == d)
|
||||||
|
isfalse(d == c)
|
||||||
|
isfalse(d == c1)
|
||||||
|
isfalse(d == c2)
|
||||||
|
isfalse(c1 == d)
|
||||||
|
isfalse(c2 == d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// named types vs not
|
||||||
|
{
|
||||||
|
var x = new(int)
|
||||||
|
var y T
|
||||||
|
var z T = x
|
||||||
|
|
||||||
|
isfalse(x == y)
|
||||||
|
istrue(x == z)
|
||||||
|
isfalse(y == z)
|
||||||
|
|
||||||
|
isfalse(y == x)
|
||||||
|
istrue(z == x)
|
||||||
|
isfalse(z == y)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
test/cmp6.go
Normal file
42
test/cmp6.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
|
// Copyright 2010 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 main
|
||||||
|
|
||||||
|
func use(bool) {}
|
||||||
|
|
||||||
|
type T1 *int
|
||||||
|
type T2 *int
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Arguments to comparison must be
|
||||||
|
// assignable one to the other (or vice versa)
|
||||||
|
// so chan int can be compared against
|
||||||
|
// directional channels but channel of different
|
||||||
|
// direction cannot be compared against each other.
|
||||||
|
var c1 chan <-int
|
||||||
|
var c2 <-chan int
|
||||||
|
var c3 chan int
|
||||||
|
|
||||||
|
use(c1 == c2) // ERROR "invalid operation"
|
||||||
|
use(c2 == c1) // ERROR "invalid operation"
|
||||||
|
use(c1 == c3)
|
||||||
|
use(c2 == c2)
|
||||||
|
use(c3 == c1)
|
||||||
|
use(c3 == c2)
|
||||||
|
|
||||||
|
// Same applies to named types.
|
||||||
|
var p1 T1
|
||||||
|
var p2 T2
|
||||||
|
var p3 *int
|
||||||
|
|
||||||
|
use(p1 == p2) // ERROR "invalid operation"
|
||||||
|
use(p2 == p1) // ERROR "invalid operation"
|
||||||
|
use(p1 == p3)
|
||||||
|
use(p2 == p2)
|
||||||
|
use(p3 == p1)
|
||||||
|
use(p3 == p2)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user