]> Cypherpunks repositories - gostls13.git/commitdiff
gc: recursive interface embedding
authorRuss Cox <rsc@golang.org>
Thu, 18 Feb 2010 19:15:36 +0000 (11:15 -0800)
committerRuss Cox <rsc@golang.org>
Thu, 18 Feb 2010 19:15:36 +0000 (11:15 -0800)
Fixes #287.

R=ken2
CC=golang-dev
https://golang.org/cl/215048

src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
test/fixedbugs/bug250.go [moved from test/bugs/bug250.go with 100% similarity]
test/fixedbugs/bug251.go [moved from test/bugs/bug251.go with 77% similarity]
test/golden.out

index 9aedf4bcceb3033878b6d693941e8917bc5bf156..5359d7252df55334e0e09665cbf9ffa08c405b3f 100644 (file)
@@ -809,23 +809,33 @@ stotype(NodeList *l, int et, Type **t)
                if(n->op != ODCLFIELD)
                        fatal("stotype: oops %N\n", n);
                if(n->right != N) {
-                       typecheck(&n->right, Etype);
-                       n->type = n->right->type;
-                       if(n->type == T) {
-                               *t0 = T;
-                               return t0;
-                       }
-                       if(n->left != N)
-                               n->left->type = n->type;
-                       n->right = N;
-                       if(n->embedded && n->type != T) {
-                               t1 = n->type;
-                               if(t1->sym == S && isptr[t1->etype])
-                                       t1 = t1->type;
-                               if(isptr[t1->etype])
-                                       yyerror("embedded type cannot be a pointer");
-                               else if(t1->etype == TFORW && t1->embedlineno == 0)
-                                       t1->embedlineno = lineno;
+                       if(et == TINTER && n->left != N) {
+                               // queue resolution of method type for later.
+                               // right now all we need is the name list.
+                               // avoids cycles for recursive interface types.
+                               n->type = typ(TINTERMETH);
+                               n->type->nod = n->right;
+                               n->right = N;
+                               queuemethod(n);
+                       } else {
+                               typecheck(&n->right, Etype);
+                               n->type = n->right->type;
+                               if(n->type == T) {
+                                       *t0 = T;
+                                       return t0;
+                               }
+                               if(n->left != N)
+                                       n->left->type = n->type;
+                               n->right = N;
+                               if(n->embedded && n->type != T) {
+                                       t1 = n->type;
+                                       if(t1->sym == S && isptr[t1->etype])
+                                               t1 = t1->type;
+                                       if(isptr[t1->etype])
+                                               yyerror("embedded type cannot be a pointer");
+                                       else if(t1->etype == TFORW && t1->embedlineno == 0)
+                                               t1->embedlineno = lineno;
+                               }
                        }
                }
 
index b9d87070c30e4fc36859d7bbce969038bbdf2ed5..642b706111042a674f61b27320a5ffb9bcc93a65 100644 (file)
@@ -462,6 +462,7 @@ enum
        // pseudo-type for frame layout
        TFUNCARGS,
        TCHANARGS,
+       TINTERMETH,
 
        NTYPE,
 };
@@ -1088,6 +1089,7 @@ Node*     typecheckconv(Node*, Node*, Type*, int, char*);
 int    checkconv(Type*, Type*, int, int*, int*, char*);
 Node*  typecheck(Node**, int);
 int    islvalue(Node*);
+void   queuemethod(Node*);
 
 /*
  *     const.c
index a7d95a9cd5a801d0fb3fa4025182c4fe295e3f37..d36775b02854828cd1bf0577871bb625986802ca 100644 (file)
@@ -51,7 +51,7 @@ typecheck(Node **np, int top)
        int et, op;
        Node *n, *l, *r;
        NodeList *args;
-       int lno, ok, ntop, ct;
+       int lno, ok, ntop;
        Type *t;
        Sym *sym;
        Val v;
index 067db0fc77796858d1e652b77717cedbc94017ab..a6b420eb66cad1d9a816bf1381a96aa346f98a59 100644 (file)
@@ -115,11 +115,25 @@ gettype(Node **np, NodeList **init)
                dump("after gettype", *np);
 }
 
-void
-walkdeflist(NodeList *l)
+static int nwalkdeftype;
+static NodeList *methodqueue;
+
+static void
+domethod(Node *n)
 {
-       for(; l; l=l->next)
-               walkdef(l->n);
+       Node *nt;
+       
+       nt = n->type->nod;
+       typecheck(&nt, Etype);
+       if(nt->type == T) {
+               // type check failed; leave empty func
+               n->type->etype = TFUNC;
+               n->type->nod = N;
+               return;
+       }
+       *n->type = *nt->type;
+       n->type->nod = N;
+       checkwidth(n->type);
 }
 
 static void
@@ -127,7 +141,9 @@ walkdeftype(Node *n)
 {
        int maplineno, embedlineno, lno;
        Type *t;
-
+       NodeList *l;
+       
+       nwalkdeftype++;
        lno = lineno;
        setlineno(n);
        n->type->sym = n->sym;
@@ -168,6 +184,28 @@ walkdeftype(Node *n)
 
 ret:
        lineno = lno;
+       
+       // if there are no type definitions going on, it's safe to
+       // try to resolve the method types for the interfaces
+       // we just read.
+       if(nwalkdeftype == 1) {
+               while((l = methodqueue) != nil) {
+                       methodqueue = nil;
+                       for(; l; l=l->next)
+                               domethod(l->n);
+               }
+       }
+       nwalkdeftype--;
+}
+
+void
+queuemethod(Node *n)
+{
+       if(nwalkdeftype == 0) {
+               domethod(n);
+               return;
+       }
+       methodqueue = list(methodqueue, n);
 }
 
 void
similarity index 100%
rename from test/bugs/bug250.go
rename to test/fixedbugs/bug250.go
similarity index 77%
rename from test/bugs/bug251.go
rename to test/fixedbugs/bug251.go
index f6365f1e630950d0dea9f39ddb28297b3ad9002f..6ddc4a5a65788896a8ea635f8b1a3e951ba2e6fe 100644 (file)
@@ -8,14 +8,14 @@ package main
 
 type I1 interface {
        m() I2
-       I2      // ERROR "loop|interface"
+       I2
 }
 
 type I2 interface {
-       I1
+       I1      // ERROR "loop|interface"
 }
 
 
-var i1 I1 = i2
+var i1 I1 = i2 // ERROR "need type assertion"
 var i2 I2
 var i2a I2 = i1
index 22abf0c4bd88c31379678d360cb48e39929036c6..cf2297e1a73e4715517199946c8d2bf5c288017c 100644 (file)
@@ -150,17 +150,3 @@ throw: interface conversion
 panic PC=xxx
 
 == bugs/
-
-=========== bugs/bug250.go
-bugs/bug250.go:14: interface type loop involving I1
-bugs/bug250.go:17: need type assertion to use I2 as I1
-       missing m() I2
-BUG: bug250
-
-=========== bugs/bug251.go
-BUG: errchk: bugs/bug251.go:11: missing expected error: 'loop|interface'
-errchk: bugs/bug251.go: unmatched error messages:
-==================================================
-bugs/bug251.go:15: interface type loop involving I1
-bugs/bug251.go:19: need type assertion to use I2 as I1
-==================================================