1
0
mirror of https://github.com/golang/go synced 2024-11-21 18:14:42 -07:00

gc: recursive interface embedding

Fixes #287.

R=ken2
CC=golang-dev
https://golang.org/cl/215048
This commit is contained in:
Russ Cox 2010-02-18 11:15:36 -08:00
parent cf015fd0b8
commit 1734cb02e7
7 changed files with 76 additions and 40 deletions

View 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;
}
}
}

View 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

View 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;

View 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

View 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

View 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
==================================================