]> Cypherpunks repositories - gostls13.git/commitdiff
bug184 - assignment compatibility in unpacked multireturn
authorRuss Cox <rsc@golang.org>
Fri, 7 Aug 2009 21:00:18 +0000 (14:00 -0700)
committerRuss Cox <rsc@golang.org>
Fri, 7 Aug 2009 21:00:18 +0000 (14:00 -0700)
R=ken
OCL=32890
CL=32894

src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/fixedbugs/bug184.go [new file with mode: 0644]

index 3488faf48f86dc3d9397c7bd6efdff0dc709af64..b041cf26f9ed9a67085f766651e5aad8767e1c27 100644 (file)
@@ -1309,6 +1309,8 @@ typecheckaste(int op, Type *tstruct, NodeList *nl)
                                yyerror("not enough arguments to %#O", op);
                                goto out;
                        }
+                       if(isddd(tl->type))
+                               goto out;
                        if(checkconv(tn->type, tl->type, 0, &xx, &yy) < 0)
                                yyerror("cannot use type %T as type %T", tn->type, tl->type);
                        tn = tn->down;
index 2298c659cba67ea3b1a3b6dcac184eadf223072d..90196ad7d60e3fa1d89c1b8529796e9d98ae1481 100644 (file)
@@ -1314,7 +1314,7 @@ ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
 {
        Type *l, *ll;
        Node *r, *a;
-       NodeList *nn, *lr0;
+       NodeList *nn, *lr0, *alist;
        Iter savel, peekl;
 
        lr0 = lr;
@@ -1326,19 +1326,32 @@ ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
 
        // 1 to many
        peekl = savel;
-       if(l != T && r != N
-       && structnext(&peekl) != T
-       && lr->next == nil
-       && eqtypenoname(r->type, *nl)) {
-               // clumsy check for differently aligned structs.
-               // now that output structs are aligned separately
-               // from the input structs, should never happen.
-               if(r->type->width != (*nl)->width)
-                       fatal("misaligned multiple return\n\t%T\n\t%T", r->type, *nl);
-               a = nodarg(*nl, fp);
-               a->type = r->type;
-               nn = list1(convas(nod(OAS, a, r), init));
-               goto ret;
+       if(l != T && r != N && structnext(&peekl) != T && lr->next == nil
+       && r->type->etype == TSTRUCT && r->type->funarg) {
+               // optimization - can do block copy
+               if(eqtypenoname(r->type, *nl)) {
+                       a = nodarg(*nl, fp);
+                       a->type = r->type;
+                       nn = list1(convas(nod(OAS, a, r), init));
+                       goto ret;
+               }
+               // conversions involved.
+               // copy into temporaries.
+               alist = nil;
+               for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
+                       a = nod(OXXX, N, N);
+                       tempname(a, l->type);
+                       alist = list(alist, a);
+               }
+               a = nod(OAS2, N, N);
+               a->list = alist;
+               a->rlist = lr;
+               typecheck(&a, Etop);
+               walkstmt(&a);
+               *init = list(*init, a);
+               lr = alist;
+               r = lr->n;
+               l = structfirst(&savel, nl);
        }
 
 loop:
@@ -1369,9 +1382,9 @@ loop:
        if(l == T || r == N) {
                if(l != T || r != N) {
                        if(l != T)
-                               yyerror("not enough arguments to %O", op);
+                               yyerror("xxx not enough arguments to %O", op);
                        else
-                               yyerror("too many arguments to %O", op);
+                               yyerror("xxx too many arguments to %O", op);
                        dumptypes(nl, "expected");
                        dumpnodetypes(lr0, "given");
                }
diff --git a/test/fixedbugs/bug184.go b/test/fixedbugs/bug184.go
new file mode 100644 (file)
index 0000000..95a76d0
--- /dev/null
@@ -0,0 +1,51 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 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
+
+import "fmt"
+
+type Buffer int
+func (*Buffer) Read() {
+}
+
+type Reader interface { Read() }
+
+func f() *Buffer {
+       return nil
+}
+
+func g() Reader {
+       // implicit interface conversion in assignment during return
+       return f()
+}
+
+func h() (b *Buffer, ok bool) {
+       return
+}
+
+func i() (r Reader, ok bool) {
+       // implicit interface conversion in multi-assignment during return
+       return h();
+}
+
+func fmter() (s string, i int, t string) {
+       return "%#x %q", 100, "hello"
+}
+
+func main() {
+       b := g();
+       bb, ok := b.(*Buffer);
+
+       b, ok = i();
+       bb, ok = b.(*Buffer);
+
+       s := fmt.Sprintf(fmter());
+       if s != "0x64 \"hello\"" {
+               panicln(s);
+       }
+}
+