From 44898c7b76cf64df61428431706102b47e8829b8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 1 Feb 2010 23:58:49 -0800 Subject: [PATCH] gc: bug250, bug251 - recursive interface types Fixes #287. R=ken2 CC=golang-dev https://golang.org/cl/199057 --- src/cmd/gc/dcl.c | 5 +- src/cmd/gc/walk.c | 100 ++++++++++++++++++++++++++------------- test/fixedbugs/bug195.go | 4 +- test/fixedbugs/bug250.go | 19 ++++++++ test/fixedbugs/bug251.go | 21 ++++++++ 5 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 test/fixedbugs/bug250.go create mode 100644 test/fixedbugs/bug251.go diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index b0b06f7d322..9aedf4bcceb 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -853,7 +853,10 @@ stotype(NodeList *l, int et, Type **t) if(et == TINTER && n->left == N) { // embedded interface - inline the methods if(n->type->etype != TINTER) { - yyerror("interface contains embedded non-interface %T", n->type); + if(n->type->etype == TFORW) + yyerror("interface type loop involving %T", n->type); + else + yyerror("interface contains embedded non-interface %T", n->type); continue; } for(t1=n->type->type; t1!=T; t1=t1->down) { diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index ffdd17a95da..31d1e3091e1 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -122,10 +122,61 @@ walkdeflist(NodeList *l) walkdef(l->n); } +static NodeList *deftypequeue; +static int intypedef; + +static void +walkdeftype(Node *n) +{ + int maplineno, embedlineno, lno; + Type *t; + + lno = lineno; + setlineno(n); + n->type->sym = n->sym; + n->typecheck = 1; + typecheck(&n->ntype, Etype); + if((t = n->ntype->type) == T) { + n->diag = 1; + goto ret; + } + + // copy new type and clear fields + // that don't come along + maplineno = n->type->maplineno; + embedlineno = n->type->embedlineno; + *n->type = *t; + t = n->type; + t->sym = n->sym; + t->local = n->local; + t->vargen = n->vargen; + t->siggen = 0; + t->printed = 0; + t->method = nil; + t->nod = N; + t->printed = 0; + t->deferwidth = 0; + + // double-check use of type as map key + // TODO(rsc): also use of type as receiver? + if(maplineno) { + lineno = maplineno; + maptype(n->type, types[TBOOL]); + } + if(embedlineno) { + lineno = embedlineno; + if(isptr[t->etype]) + yyerror("embedded type cannot be a pointer"); + } + +ret: + lineno = lno; +} + void walkdef(Node *n) { - int lno, maplineno, embedlineno; + int lno; NodeList *init; Node *e; Type *t; @@ -214,40 +265,21 @@ walkdef(Node *n) n->walkdef = 1; n->type = typ(TFORW); n->type->sym = n->sym; - n->typecheck = 1; - typecheck(&n->ntype, Etype); - if((t = n->ntype->type) == T) { - n->diag = 1; - goto ret; - } - - // copy new type and clear fields - // that don't come along - maplineno = n->type->maplineno; - embedlineno = n->type->embedlineno; - *n->type = *t; - t = n->type; - t->sym = n->sym; - t->local = n->local; - t->vargen = n->vargen; - t->siggen = 0; - t->printed = 0; - t->method = nil; - t->nod = N; - t->printed = 0; - t->deferwidth = 0; - - // double-check use of type as map key - // TODO(rsc): also use of type as receiver? - if(maplineno) { - lineno = maplineno; - maptype(n->type, types[TBOOL]); - } - if(embedlineno) { - lineno = embedlineno; - if(isptr[t->etype]) - yyerror("embedded type cannot be a pointer"); + intypedef++; + if(intypedef > 1) + deftypequeue = list(deftypequeue, n); + else { + walkdeftype(n); + while(deftypequeue != nil) { + NodeList *l; + + l = deftypequeue; + deftypequeue = nil; + for(; l; l=l->next) + walkdeftype(l->n); + } } + intypedef--; break; case OPACK: diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go index 27bbbd354a6..221a2eb0986 100644 --- a/test/fixedbugs/bug195.go +++ b/test/fixedbugs/bug195.go @@ -19,9 +19,9 @@ type I4 interface { } type I5 interface { - I6 + I6 // ERROR "interface" } type I6 interface { - I5 // ERROR "interface" + I5 } diff --git a/test/fixedbugs/bug250.go b/test/fixedbugs/bug250.go new file mode 100644 index 00000000000..cd28642bfc9 --- /dev/null +++ b/test/fixedbugs/bug250.go @@ -0,0 +1,19 @@ +// $G $D/$F.go || echo BUG: bug250 + +// Copyright 2010 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 + +type I1 interface { + m() I2 +} + +type I2 interface { + I1 +} + +var i1 I1 = i2 +var i2 I2 +var i2a I2 = i1 diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go new file mode 100644 index 00000000000..1dc712fa7c3 --- /dev/null +++ b/test/fixedbugs/bug251.go @@ -0,0 +1,21 @@ +// errchk $G $D/$F.go + +// Copyright 2010 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 + +type I1 interface { + m() I2 + I2 // ERROR "loop" +} + +type I2 interface { + I1 +} + + +var i1 I1 = i2 +var i2 I2 +var i2a I2 = i1