Commit 1734cb02 authored by Russ Cox's avatar Russ Cox

gc: recursive interface embedding

Fixes #287.

R=ken2
CC=golang-dev
https://golang.org/cl/215048
parent cf015fd0
...@@ -809,23 +809,33 @@ stotype(NodeList *l, int et, Type **t) ...@@ -809,23 +809,33 @@ stotype(NodeList *l, int et, Type **t)
if(n->op != ODCLFIELD) if(n->op != ODCLFIELD)
fatal("stotype: oops %N\n", n); fatal("stotype: oops %N\n", n);
if(n->right != N) { if(n->right != N) {
typecheck(&n->right, Etype); if(et == TINTER && n->left != N) {
n->type = n->right->type; // queue resolution of method type for later.
if(n->type == T) { // right now all we need is the name list.
*t0 = T; // avoids cycles for recursive interface types.
return t0; n->type = typ(TINTERMETH);
} n->type->nod = n->right;
if(n->left != N) n->right = N;
n->left->type = n->type; queuemethod(n);
n->right = N; } else {
if(n->embedded && n->type != T) { typecheck(&n->right, Etype);
t1 = n->type; n->type = n->right->type;
if(t1->sym == S && isptr[t1->etype]) if(n->type == T) {
t1 = t1->type; *t0 = T;
if(isptr[t1->etype]) return t0;
yyerror("embedded type cannot be a pointer"); }
else if(t1->etype == TFORW && t1->embedlineno == 0) if(n->left != N)
t1->embedlineno = lineno; 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;
}
} }
} }
......
...@@ -462,6 +462,7 @@ enum ...@@ -462,6 +462,7 @@ enum
// pseudo-type for frame layout // pseudo-type for frame layout
TFUNCARGS, TFUNCARGS,
TCHANARGS, TCHANARGS,
TINTERMETH,
NTYPE, NTYPE,
}; };
...@@ -1088,6 +1089,7 @@ Node* typecheckconv(Node*, Node*, Type*, int, char*); ...@@ -1088,6 +1089,7 @@ Node* typecheckconv(Node*, Node*, Type*, int, char*);
int checkconv(Type*, Type*, int, int*, int*, char*); int checkconv(Type*, Type*, int, int*, int*, char*);
Node* typecheck(Node**, int); Node* typecheck(Node**, int);
int islvalue(Node*); int islvalue(Node*);
void queuemethod(Node*);
/* /*
* const.c * const.c
......
...@@ -51,7 +51,7 @@ typecheck(Node **np, int top) ...@@ -51,7 +51,7 @@ typecheck(Node **np, int top)
int et, op; int et, op;
Node *n, *l, *r; Node *n, *l, *r;
NodeList *args; NodeList *args;
int lno, ok, ntop, ct; int lno, ok, ntop;
Type *t; Type *t;
Sym *sym; Sym *sym;
Val v; Val v;
......
...@@ -115,11 +115,25 @@ gettype(Node **np, NodeList **init) ...@@ -115,11 +115,25 @@ gettype(Node **np, NodeList **init)
dump("after gettype", *np); dump("after gettype", *np);
} }
void static int nwalkdeftype;
walkdeflist(NodeList *l) static NodeList *methodqueue;
static void
domethod(Node *n)
{ {
for(; l; l=l->next) Node *nt;
walkdef(l->n);
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 static void
...@@ -127,7 +141,9 @@ walkdeftype(Node *n) ...@@ -127,7 +141,9 @@ walkdeftype(Node *n)
{ {
int maplineno, embedlineno, lno; int maplineno, embedlineno, lno;
Type *t; Type *t;
NodeList *l;
nwalkdeftype++;
lno = lineno; lno = lineno;
setlineno(n); setlineno(n);
n->type->sym = n->sym; n->type->sym = n->sym;
...@@ -168,6 +184,28 @@ walkdeftype(Node *n) ...@@ -168,6 +184,28 @@ walkdeftype(Node *n)
ret: ret:
lineno = lno; 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 void
......
...@@ -8,14 +8,14 @@ package main ...@@ -8,14 +8,14 @@ package main
type I1 interface { type I1 interface {
m() I2 m() I2
I2 // ERROR "loop|interface" I2
} }
type I2 interface { type I2 interface {
I1 I1 // ERROR "loop|interface"
} }
var i1 I1 = i2 var i1 I1 = i2 // ERROR "need type assertion"
var i2 I2 var i2 I2
var i2a I2 = i1 var i2a I2 = i1
...@@ -150,17 +150,3 @@ throw: interface conversion ...@@ -150,17 +150,3 @@ throw: interface conversion
panic PC=xxx panic PC=xxx
== bugs/ == 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
==================================================
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment