]> Cypherpunks.ru repositories - gostls13.git/commitdiff
gc: implement new comparison rule
authorRuss Cox <rsc@golang.org>
Mon, 13 Sep 2010 19:42:47 +0000 (15:42 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 13 Sep 2010 19:42:47 +0000 (15:42 -0400)
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

src/cmd/gc/typecheck.c
test/cmp1.go
test/cmp6.go [new file with mode: 0644]

index ea2cf49973089b72f370544a9999e583f8624754..8ea0f9dca3dfbf9c5aa5aaf9a7767497cf623b5e 100644 (file)
@@ -63,7 +63,7 @@ typechecklist(NodeList *l, int top)
 Node*
 typecheck(Node **np, int top)
 {
-       int et, op, ptr;
+       int et, aop, op, ptr;
        Node *n, *l, *r;
        NodeList *args;
        int lno, ok, ntop;
@@ -350,6 +350,26 @@ reswitch:
                et = t->etype;
                if(et == TIDEAL)
                        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)) {
                badbinary:
                        defaultlit2(&l, &r, 1);
index db0a486dd339f6f6df3688a02a725bade8d5f77b..698544c58219413651c0533fc7a36e457b45c1a3 100644 (file)
@@ -26,6 +26,8 @@ func istrue(b bool) {
        }
 }
 
+type T *int
+
 func main() {
        var a []int
        var b map[string]int
@@ -55,6 +57,24 @@ func main() {
        isfalse(ib == id)
        istrue(ic == id)
        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.
        var g uint64 = 123
@@ -73,4 +93,38 @@ func main() {
                println("m[ic] = ", 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)
+       }
 }
diff --git a/test/cmp6.go b/test/cmp6.go
new file mode 100644 (file)
index 0000000..981a859
--- /dev/null
@@ -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)
+}