1
0
mirror of https://github.com/golang/go synced 2024-11-25 04:57:56 -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:
Russ Cox 2010-09-13 15:42:47 -04:00
parent c3900387db
commit 23bd214aee
3 changed files with 117 additions and 1 deletions

View File

@ -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);

View File

@ -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
@ -56,6 +58,24 @@ func main() {
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
var h int64 = 123 var h int64 = 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
View 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)
}