From 480f51243c0b21f4631efe15a5b61c50eea4e7ed Mon Sep 17 00:00:00 2001
From: Russ Cox <rsc@golang.org>
Date: Thu, 25 Jun 2009 21:02:39 -0700
Subject: [PATCH] bug165

R=ken
OCL=30783
CL=30783
---
 src/cmd/gc/dcl.c                   | 11 +++++++++++
 src/cmd/gc/go.h                    |  2 ++
 src/cmd/gc/subr.c                  | 15 +++++++++++++--
 test/{bugs => fixedbugs}/bug165.go |  6 +++++-
 test/golden.out                    |  4 ----
 5 files changed, 31 insertions(+), 7 deletions(-)
 rename test/{bugs => fixedbugs}/bug165.go (72%)

diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index c33ead564d..38bc022d28 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -93,6 +93,7 @@ updatetype(Type *n, Type *t)
 {
 	Sym *s;
 	int local;
+	int maplineno, lno;
 
 	s = n->sym;
 	if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n)
@@ -124,6 +125,7 @@ updatetype(Type *n, Type *t)
 	//	type n t;
 	// copy t, but then zero out state associated with t
 	// that is no longer associated with n.
+	maplineno = n->maplineno;
 	local = n->local;
 	*n = *t;
 	n->sym = s;
@@ -133,6 +135,7 @@ updatetype(Type *n, Type *t)
 	n->method = nil;
 	n->vargen = 0;
 	n->nod = N;
+
 	// catch declaration of incomplete type
 	switch(n->etype) {
 	case TFORWSTRUCT:
@@ -141,6 +144,14 @@ updatetype(Type *n, Type *t)
 	default:
 		checkwidth(n);
 	}
+	
+	// double-check use of type as map key
+	if(maplineno) {
+		lno = lineno;
+		lineno = maplineno;
+		maptype(n, types[TBOOL]);
+		lineno = lno;
+	}
 }
 
 
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 876a03a93a..3b521dd2dd 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -171,6 +171,8 @@ struct	Type
 
 	// TARRAY
 	int32	bound;		// negative is dynamic array
+	
+	int32	maplineno;	// first use of TFORW as map key
 };
 #define	T	((Type*)0)
 
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 9dfb445c63..2e0c6b07da 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -345,8 +345,19 @@ maptype(Type *key, Type *val)
 {
 	Type *t;
 
-	if(key != nil && key->etype != TANY && algtype(key) == ANOEQ)
-		yyerror("invalid map key type %T", key);
+	if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) {
+		if(key->etype == TFORW) {
+			// map[key] used during definition of key.
+			// postpone check until key is fully defined.
+			// if there are multiple uses of map[key]
+			// before key is fully defined, the error
+			// will only be printed for the first one.
+			// good enough.
+			if(key->maplineno == 0)
+				key->maplineno = lineno;
+		} else
+			yyerror("invalid map key type %T", key);
+	}
 	t = typ(TMAP);
 	t->down = key;
 	t->type = val;
diff --git a/test/bugs/bug165.go b/test/fixedbugs/bug165.go
similarity index 72%
rename from test/bugs/bug165.go
rename to test/fixedbugs/bug165.go
index 02a6c379b4..8ce67a46db 100644
--- a/test/bugs/bug165.go
+++ b/test/fixedbugs/bug165.go
@@ -7,5 +7,9 @@
 package main
 
 type I interface {
-	m(map[I] bool)
+	m(map[I] bool);	// ok
+}
+
+type S struct {
+	m map[S] bool;	// ERROR "map key type"
 }
diff --git a/test/golden.out b/test/golden.out
index 09ac96269a..695a68cd41 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -111,10 +111,6 @@ BUG: should not compile
 =========== bugs/bug164.go
 BUG: should not compile
 
-=========== bugs/bug165.go
-bugs/bug165.go:6: invalid map key type I
-BUG: should compile
-
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: constant -3 overflows uint
 
-- 
2.30.9