diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 6f387c3b030..1212b42172a 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -182,6 +182,9 @@ struct Type int32 maplineno; // first use of TFORW as map key int32 embedlineno; // first use of TFORW as embedded type + + // for TFORW, where to copy the eventual value to + NodeList *copyto; }; #define T ((Type*)0) @@ -1250,9 +1253,7 @@ int islvalue(Node *n); Node* typecheck(Node **np, int top); void typechecklist(NodeList *l, int top); Node* typecheckdef(Node *n); -void resumetypecopy(void); void copytype(Node *n, Type *t); -void defertypecopy(Node *n, Type *t); void queuemethod(Node *n); /* diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 73029664209..e6e75589580 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -349,7 +349,6 @@ main(int argc, char *argv[]) for(l=xtop; l; l=l->next) if(l->n->op == ODCL || l->n->op == OAS) typecheck(&l->n, Etop); - resumetypecopy(); resumecheckwidth(); // Phase 3: Type check function bodies. diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 02d6cc47772..cc4faf5a7a8 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -31,7 +31,6 @@ static void checkassign(Node*); static void checkassignlist(NodeList*); static void stringtoarraylit(Node**); static Node* resolve(Node*); -static Type* getforwtype(Node*); static NodeList* typecheckdefstack; @@ -237,7 +236,7 @@ typecheck1(Node **np, int top) Node *n, *l, *r; NodeList *args; int ok, ntop; - Type *t, *tp, *ft, *missing, *have, *badtype; + Type *t, *tp, *missing, *have, *badtype; Val v; char *why; @@ -249,10 +248,6 @@ typecheck1(Node **np, int top) goto error; } - // a dance to handle forward-declared recursive pointer types. - if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T) - defertypecopy(n, ft); - typecheckdef(n); n->realtype = n->type; if(n->op == ONONAME) @@ -2616,26 +2611,6 @@ stringtoarraylit(Node **np) *np = nn; } -static Type* -getforwtype(Node *n) -{ - Node *f1, *f2; - - for(f2=n; ; n=n->ntype) { - if((n = resolve(n)) == N || n->op != OTYPE) - return T; - - if(n->type != T && n->type->etype == TFORW) - return n->type; - - // Check for ntype cycle. - if((f2 = resolve(f2)) != N && (f1 = resolve(f2->ntype)) != N) { - f2 = resolve(f1->ntype); - if(f1 == n || f2 == n) - return T; - } - } -} static int ntypecheckdeftype; static NodeList *methodqueue; @@ -2673,49 +2648,24 @@ domethod(Node *n) checkwidth(n->type); } -typedef struct NodeTypeList NodeTypeList; -struct NodeTypeList { - Node *n; - Type *t; - NodeTypeList *next; -}; - -static NodeTypeList *dntq; -static NodeTypeList *dntend; - -void -defertypecopy(Node *n, Type *t) -{ - NodeTypeList *ntl; - - if(n == N || t == T) - return; - - ntl = mal(sizeof *ntl); - ntl->n = n; - ntl->t = t; - ntl->next = nil; - - if(dntq == nil) - dntq = ntl; - else - dntend->next = ntl; - - dntend = ntl; -} - -void -resumetypecopy(void) -{ - NodeTypeList *l; - - for(l=dntq; l; l=l->next) - copytype(l->n, l->t); -} +static NodeList *mapqueue; void copytype(Node *n, Type *t) { + int maplineno, embedlineno, lno; + NodeList *l; + + if(t->etype == TFORW) { + // This type isn't computed yet; when it is, update n. + t->copyto = list(t->copyto, n); + return; + } + + maplineno = n->type->maplineno; + embedlineno = n->type->embedlineno; + + l = n->type->copyto; *n->type = *t; t = n->type; @@ -2728,12 +2678,32 @@ copytype(Node *n, Type *t) t->nod = N; t->printed = 0; t->deferwidth = 0; + t->copyto = nil; + + // Update nodes waiting on this type. + for(; l; l=l->next) + copytype(l->n, t); + + // Double-check use of type as embedded type. + lno = lineno; + if(embedlineno) { + lineno = embedlineno; + if(isptr[t->etype]) + yyerror("embedded type cannot be a pointer"); + } + lineno = lno; + + // Queue check for map until all the types are done settling. + if(maplineno) { + t->maplineno = maplineno; + mapqueue = list(mapqueue, n); + } } static void typecheckdeftype(Node *n) { - int maplineno, embedlineno, lno; + int lno; Type *t; NodeList *l; @@ -2752,26 +2722,12 @@ typecheckdeftype(Node *n) goto ret; } - maplineno = n->type->maplineno; - embedlineno = n->type->embedlineno; - // copy new type and clear fields // that don't come along. // anything zeroed here must be zeroed in // typedcl2 too. copytype(n, t); - // double-check use of type as map key. - 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; @@ -2784,6 +2740,11 @@ ret: for(; l; l=l->next) domethod(l->n); } + for(l=mapqueue; l; l=l->next) { + lineno = l->n->type->maplineno; + maptype(l->n->type, types[TBOOL]); + } + lineno = lno; } ntypecheckdeftype--; } diff --git a/test/fixedbugs/bug443.go b/test/fixedbugs/bug443.go new file mode 100644 index 00000000000..b67bd8cb875 --- /dev/null +++ b/test/fixedbugs/bug443.go @@ -0,0 +1,17 @@ +// compile + +// Copyright 2012 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. + +// Was failing to compile with 'invalid receiver' due to +// incomplete type definition evaluation. Issue 3709. + +package p + +type T1 struct { F *T2 } +type T2 T1 + +type T3 T2 +func (*T3) M() // was invalid receiver + diff --git a/test/map1.go b/test/map1.go index 369e49da5d0..6f1a1c8ac01 100644 --- a/test/map1.go +++ b/test/map1.go @@ -41,4 +41,22 @@ var ( _ map[[]int]v // ERROR "invalid map key" _ map[func()]v // ERROR "invalid map key" _ map[map[int]int]v // ERROR "invalid map key" + _ map[T1]v // ERROR "invalid map key" + _ map[T2]v // ERROR "invalid map key" + _ map[T3]v // ERROR "invalid map key" + _ map[T4]v // ERROR "invalid map key" + _ map[T5]v + _ map[T6]v + _ map[T7]v + _ map[T8]v ) + +type T1 []int +type T2 struct { F T1 } +type T3 []T4 +type T4 struct { F T3 } + +type T5 *int +type T6 struct { F T5 } +type T7 *T4 +type T8 struct { F *T7 }