summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-02-18 11:15:36 -0800
committerRuss Cox <rsc@golang.org>2010-02-18 11:15:36 -0800
commitbbc34623c6a1c52a9b61666668a2b64a72d68b32 (patch)
treecc57c91c8d579a1697848d13ed1bf5d76326d296
parent48735396db1250b4ba2c4371c84c3a1e2dc50379 (diff)
downloadgo-bbc34623c6a1c52a9b61666668a2b64a72d68b32.tar.gz
gc: recursive interface embedding
Fixes issue 287. R=ken2 CC=golang-dev http://codereview.appspot.com/215048
-rw-r--r--src/cmd/gc/dcl.c44
-rw-r--r--src/cmd/gc/go.h2
-rw-r--r--src/cmd/gc/typecheck.c2
-rw-r--r--src/cmd/gc/walk.c48
-rw-r--r--test/fixedbugs/bug250.go (renamed from test/bugs/bug250.go)0
-rw-r--r--test/fixedbugs/bug251.go (renamed from test/bugs/bug251.go)6
-rw-r--r--test/golden.out14
7 files changed, 76 insertions, 40 deletions
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 9aedf4bcc..5359d7252 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -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;
+ }
}
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index b9d87070c..642b70611 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -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
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index a7d95a9cd..d36775b02 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -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;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 067db0fc7..a6b420eb6 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -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
diff --git a/test/bugs/bug250.go b/test/fixedbugs/bug250.go
index cd28642bf..cd28642bf 100644
--- a/test/bugs/bug250.go
+++ b/test/fixedbugs/bug250.go
diff --git a/test/bugs/bug251.go b/test/fixedbugs/bug251.go
index f6365f1e6..6ddc4a5a6 100644
--- a/test/bugs/bug251.go
+++ b/test/fixedbugs/bug251.go
@@ -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
diff --git a/test/golden.out b/test/golden.out
index 22abf0c4b..cf2297e1a 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -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
-==================================================