From 0e203bce341829d8761176c5f6763a0523a610cf Mon Sep 17 00:00:00 2001
From: Leo Tenenbaum <pommicket@gmail.com>
Date: Mon, 6 Jan 2020 16:43:55 -0500
Subject: fixed bug with cgen structs

---
 cgen.c           |  12 +++----
 copy.c           |   7 ++--
 decls_cgen.c     |  70 ++++++++++++++++++++++---------------
 eval.c           |  34 +++++++++++++-----
 identifiers.c    |   1 +
 instance_table.c |   6 ++++
 package.c        |   7 ++--
 parse.c          |   8 +++--
 test.toc         |   2 ++
 typedefs_cgen.c  | 103 +++++++++++++++++++++++++++++++++++++++++++------------
 types.c          |  35 +++++++++++--------
 types.h          |  12 +++++--
 12 files changed, 209 insertions(+), 88 deletions(-)

diff --git a/cgen.c b/cgen.c
index 958b781..b94cdfc 100644
--- a/cgen.c
+++ b/cgen.c
@@ -5,7 +5,7 @@
 */
 static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *ev, Allocator *allocr) {
 	g->outc = out;
-	g->ident_counter = 1; /* some places use 0 to mean no id */
+	g->ident_counter = 0;
 	g->main_ident = ident_get(ids, "main");
 	g->evalr = ev;
 	g->will_indent = true;
@@ -760,7 +760,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
 	case EXPR_WHILE:
 	case EXPR_EACH:
 	case EXPR_BLOCK: {
-		id = g->ident_counter++;
+		id = ++g->ident_counter;
 		
 		cgen_ident_id_to_str(ret_name, id);
 		char *p = ret_name + strlen(ret_name);
@@ -1026,7 +1026,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
 		}
 		if (cgen_uses_ptr(&e->type)
 			&& e->type.kind != TYPE_TUPLE) {
-			e->call.c.id = g->ident_counter++;
+			e->call.c.id = ++g->ident_counter;
 			if (!cgen_type_pre(g, &e->type, e->where)) return false;
 			cgen_write(g, " ");
 			cgen_ident_id(g, e->call.c.id);
@@ -1070,8 +1070,8 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
 		break;
 	case EXPR_SLICE: {
 		SliceExpr *s = &e->slice;
-	    IdentID s_id = e->slice.c.id = g->ident_counter++;
-		IdentID from_id = g->ident_counter++;
+	    IdentID s_id = e->slice.c.id = ++g->ident_counter;
+		IdentID from_id = ++g->ident_counter;
 		if (!cgen_expr_pre(g, s->of))
 			return false;
 		if (s->from && !cgen_expr_pre(g, s->from))
@@ -1135,7 +1135,7 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
 		if (!cgen_val_pre(g, e->val, &e->type, e->where))
 			return false;
 		if (!cgen_type_pre(g, &e->type, e->where)) return false;
-		e->val_c_id = g->ident_counter++;
+		e->val_c_id = ++g->ident_counter;
 		cgen_write(g, " ");
 		cgen_ident_id(g, e->val_c_id);
 		if (!cgen_type_post(g, &e->type, e->where)) return false;
diff --git a/copy.c b/copy.c
index 1b3c5ac..c13dfa1 100644
--- a/copy.c
+++ b/copy.c
@@ -38,6 +38,8 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) {
 	case TYPE_SLICE:
 	case TYPE_VOID:
 	case TYPE_UNKNOWN:
+	case TYPE_PKG:
+	case TYPE_TYPE:
 		*out = *in;
 		break;
 	case TYPE_ARR: {
@@ -55,9 +57,6 @@ static void copy_val(Allocator *a, Value *out, Value *in, Type *t) {
 		out->struc = allocr_malloc(a, bytes);
 		memcpy(out->struc, in->struc, bytes);
 	} break;
-	case TYPE_TYPE:
-		*out = *in;
-		break;
 	case TYPE_EXPR:
 		assert(0);
 	}
@@ -268,7 +267,7 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
 			copy_expr(c, sout->to = allocr_malloc(a, sizeof *sout->to), sin->to);
 	} break;
 	case EXPR_PKG:
-		copy_expr(c, out->pkg.name = allocr_malloc(a, sizeof *out->pkg.name), in->pkg.name);
+		copy_expr(c, out->pkg.name_expr = allocr_malloc(a, sizeof *out->pkg.name_expr), in->pkg.name_expr);
 		break;
 	case EXPR_TYPE:
 		copy_type(c, &out->typeval, &in->typeval);
diff --git a/decls_cgen.c b/decls_cgen.c
index 94e65df..85c574c 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -7,6 +7,41 @@ static bool cgen_decls_stmt(CGenerator *g, Statement *s);
 static bool cgen_decls_block(CGenerator *g, Block *b);
 static bool cgen_decls_decl(CGenerator *g, Declaration *d);
 
+static bool cgen_decls_type(CGenerator *g, Type *type, Location where) {
+	if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
+		return true;
+	if (type->kind == TYPE_STRUCT) {
+		StructDef *sdef = type->struc;
+		if (!(sdef->flags & STRUCT_DEF_CGENERATED)) {
+			/* generate struct definition */
+			cgen_write(g, "struct ");
+			if (sdef->c.name) {
+				cgen_ident(g, sdef->c.name);
+			} else {
+				assert(sdef->c.id);
+				cgen_ident_id(g, sdef->c.id);
+			}
+			cgen_write(g, "{");
+			cgen_nl(g);
+			++g->indent_lvl;
+			arr_foreach(sdef->fields, Field, f) {
+				if (!cgen_type_pre(g, f->type, where)) return false;
+				cgen_write(g, " ");
+				cgen_ident(g, f->name);
+				if (!cgen_type_post(g, f->type, where)) return false;
+				cgen_write(g, ";");
+				cgen_nl(g);
+			}
+			--g->indent_lvl;
+			cgen_write(g, "};");
+			cgen_nl(g);
+			sdef->flags |= STRUCT_DEF_CGENERATED;
+		}
+	}
+	cgen_recurse_into_type(cgen_decls_type, g, type, where);
+	return true;
+}
+
 static bool cgen_fn_decl(CGenerator *g, FnExpr *f, Location where, U64 instance, U64 which_are_const) {
 	if (cgen_should_gen_fn(f)) {
 		if (!fn_enter(f, 0))
@@ -57,7 +92,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
 		FnExpr *f = e->fn;
 		f->c.name = NULL;
 		if (!f->c.id)
-			f->c.id = g->ident_counter++;
+			f->c.id = ++g->ident_counter;
 		FnType *fn_type = &e->type.fn;
 		if (fn_type->constness) {
 			if (!cgen_decls_fn_instances(g, e))
@@ -69,33 +104,12 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
 	} break;
 	case EXPR_TYPE: {
 		Type *type = &e->typeval;
-		if (type->kind == TYPE_STRUCT) {
-			StructDef *sdef = type->struc;
-			if (!(sdef->flags & STRUCT_DEF_CGENERATED)) {
-				/* generate struct definition */
-				cgen_write(g, "struct ");
-				if (sdef->c.name)
-					cgen_ident(g, sdef->c.name);
-				else
-					cgen_ident_id(g, sdef->c.id);
-				cgen_write(g, "{");
-				cgen_nl(g);
-				++g->indent_lvl;
-				arr_foreach(sdef->fields, Field, f) {
-					if (!cgen_type_pre(g, f->type, e->where)) return false;
-					cgen_write(g, " ");
-					cgen_ident(g, f->name);
-					if (!cgen_type_post(g, f->type, e->where)) return false;
-					cgen_write(g, ";");
-					cgen_nl(g);
-				}
-				--g->indent_lvl;
-				cgen_write(g, "};");
-				cgen_nl(g);
-				sdef->flags |= STRUCT_DEF_CGENERATED;
-			}
-		}
+		if (!cgen_decls_type(g, type, e->where))
+			return false;
 	} break;
+	case EXPR_CAST:
+		if (!cgen_decls_type(g, &e->cast.type, e->where))
+			return false;
 	default:
 		break;
 	}
@@ -117,6 +131,8 @@ static bool cgen_decls_block(CGenerator *g, Block *b) {
 }
 
 static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
+	if (!cgen_decls_type(g, &d->type, d->where))
+		return false;
 	if (cgen_fn_is_direct(g, d)) {
 		d->expr.fn->c.name = d->idents[0];
 		if (d->expr.type.fn.constness) {
diff --git a/eval.c b/eval.c
index ded9b5b..d6a29a8 100644
--- a/eval.c
+++ b/eval.c
@@ -56,6 +56,7 @@ static size_t compiler_sizeof_builtin(BuiltinType b) {
 }
 
 static size_t compiler_alignof(Type *t) {
+	Value v;
 	assert(t->flags & TYPE_IS_RESOLVED);
 	switch (t->kind) {
 	case TYPE_BUILTIN:
@@ -63,11 +64,11 @@ static size_t compiler_alignof(Type *t) {
 	case TYPE_VOID:
 		return 1;
 	case TYPE_FN:
-		return sizeof(FnExpr *);
+		return sizeof v.fn;
 	case TYPE_PTR:
-		return sizeof(void *);
+		return sizeof v.ptr;
 	case TYPE_TUPLE:
-		return sizeof(Value *);
+		return sizeof v.tuple;
 	case TYPE_ARR:
 		return compiler_alignof(t->arr.of);
 	case TYPE_SLICE:
@@ -76,7 +77,9 @@ static size_t compiler_alignof(Type *t) {
 		else
 			return sizeof(size_t);
 	case TYPE_TYPE:
-		return sizeof(Type *);
+		return sizeof v.type;
+	case TYPE_PKG:
+		return sizeof v.pkg;
 	case TYPE_STRUCT: {
 		/* assume the align of a struct is (at most) the greatest align out of its children's */
 		size_t align = 1;
@@ -118,22 +121,25 @@ static void eval_struct_find_offsets(Type *t) {
 
 /* size of a type at compile time */
 static size_t compiler_sizeof(Type *t) {
+	Value v;
 	assert(t->flags & TYPE_IS_RESOLVED);
 	switch (t->kind) {
 	case TYPE_BUILTIN:
 		return compiler_sizeof_builtin(t->builtin);
 	case TYPE_FN:
-		return sizeof(FnExpr *);
+		return sizeof v.fn;
 	case TYPE_PTR:
-		return sizeof(void *);
+		return sizeof v.ptr;
 	case TYPE_ARR:
 		return t->arr.n * compiler_sizeof(t->arr.of);
 	case TYPE_TUPLE:
-		return sizeof(Value *);
+		return sizeof v.tuple;
 	case TYPE_SLICE:
-		return sizeof(Slice);
+		return sizeof v.slice;
 	case TYPE_TYPE:
-		return sizeof(Type *);
+		return sizeof v.type;
+	case TYPE_PKG:
+		return sizeof v.pkg;
 	case TYPE_STRUCT: {
 		eval_struct_find_offsets(t);
 		return t->struc->size;
@@ -318,6 +324,10 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
 	case TYPE_PTR:
 		fprintf(f, "<pointer: %p>", *(void **)p);
 		break;
+	case TYPE_PKG: {
+		Package *pkg = *(Package **)p;
+		fprintf(f, "<package at %p>", (void *)pkg);
+	} break;
 	case TYPE_SLICE: {
 		fprintf(f, "["); /* TODO: change? when slice initializers are added */
 		Slice slice = *(Slice *)p;
@@ -614,6 +624,9 @@ static void eval_deref(Value *v, void *ptr, Type *type) {
 	case TYPE_TYPE:
 		v->type = *(Type **)ptr;
 		break;
+	case TYPE_PKG:
+		v->pkg = *(Package **)ptr;
+		break;
 	case TYPE_VOID:
 	case TYPE_UNKNOWN:
 	case TYPE_EXPR:
@@ -652,6 +665,9 @@ static void eval_deref_set(void *set, Value *to, Type *type) {
 	case TYPE_TYPE:
 		*(Type **)set = to->type;
 		break;
+	case TYPE_PKG:
+		*(Package **)set = to->pkg;
+		break;
 	case TYPE_VOID:
 	case TYPE_UNKNOWN:
 	case TYPE_EXPR:
diff --git a/identifiers.c b/identifiers.c
index a7750a7..3bb3eb1 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -36,6 +36,7 @@ static Identifier ident_new(Identifiers *ids, Identifier parent, unsigned char i
 	for (size_t i = 0; i < TREE_NCHILDREN; ++i)
 		tree->children[i] = NULL;
 	tree->decls = NULL;
+	tree->pkg = NULL;
 #endif
 	tree->parent = parent;
 	if (parent)
diff --git a/instance_table.c b/instance_table.c
index 3c859ac..aeb72d3 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -191,6 +191,10 @@ static U64 val_ptr_hash(void *v, Type *t) {
 		}
 		return hash;
 	}
+	case TYPE_PKG: {
+		Package *pkg = *(Package **)v;
+		return (U64)pkg;
+	} break;
 	case TYPE_EXPR: break;
 	}
 	assert(0);
@@ -272,6 +276,8 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
 				return false;
 		}
 	    return true;
+	case TYPE_PKG:
+		return *(Package **)u == *(Package **)v;
 	case TYPE_EXPR: break;
 	}
 	assert(0);
diff --git a/package.c b/package.c
index 8c8ee77..de0ab43 100644
--- a/package.c
+++ b/package.c
@@ -261,6 +261,10 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where)
 		if (!export_fn_ptr(ex, *(FnExpr **)val, where))
 			return false;
 		break;
+	case TYPE_PKG: {
+		Package *pkg = *(Package **)val;
+		export_ident(ex, pkg->name);
+	} break;
 	case TYPE_UNKNOWN:
 	case TYPE_EXPR:
 		assert(0);
@@ -406,8 +410,7 @@ static bool export_expr(Exporter *ex, Expression *e) {
 			return false;
 	} break;
 	case EXPR_PKG:
-		if (!export_expr(ex, e->pkg.name))
-			return false;
+		export_ident(ex, e->pkg.name_ident);
 		break;
 	case EXPR_SLICE: {
 		SliceExpr *s = &e->slice;
diff --git a/parse.c b/parse.c
index 0efe4ff..9cf3059 100644
--- a/parse.c
+++ b/parse.c
@@ -1013,7 +1013,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
 		case KW_PKG:
 			++t->token;
 			e->kind = EXPR_PKG;
-			if (!parse_expr(p, e->pkg.name = parser_malloc(p, sizeof *e->pkg.name), expr_find_end(p, 0)))
+			if (!parse_expr(p, e->pkg.name_expr = parser_malloc(p, sizeof *e->pkg.name_expr), expr_find_end(p, 0)))
 				return false;
 			return true;
 		case KW_FN: {
@@ -2236,7 +2236,11 @@ static void fprint_expr(FILE *out, Expression *e) {
 		break;
 	case EXPR_PKG:
 		fprintf(out, "(pkg ");
-		fprint_expr(out, e->pkg.name);
+		if (found_type) {
+			fprint_ident(out, e->pkg.name_ident);
+		} else {
+			fprint_expr(out, e->pkg.name_expr);
+		}
 		fprintf(out, ")");
 		break;
 	}
diff --git a/test.toc b/test.toc
index d3f0f3e..e88affb 100644
--- a/test.toc
+++ b/test.toc
@@ -17,4 +17,6 @@ main ::= fn() {
 	 puti(a); puti(b);
 	 c:x = 7;
 	 d:x = 18;
+	 k : [5]struct {x: int; y: int;};
+	 puti(k[0].x);
 };
\ No newline at end of file
diff --git a/typedefs_cgen.c b/typedefs_cgen.c
index 3050409..531fb0d 100644
--- a/typedefs_cgen.c
+++ b/typedefs_cgen.c
@@ -7,6 +7,75 @@ static bool typedefs_stmt(CGenerator *g, Statement *s);
 static bool typedefs_decl(CGenerator *g, Declaration *d);
 static bool typedefs_expr(CGenerator *g, Expression *e);
 
+#define cgen_recurse_into_type(f, g, type, extra)	\
+	switch (type->kind) {							\
+	case TYPE_STRUCT:								\
+		arr_foreach(type->struc->fields, Field, fl)	\
+			if (!f(g, fl->type, extra))				\
+				return false;						\
+		break;										\
+	case TYPE_FN:									\
+		arr_foreach(type->fn.types, Type, sub) {	\
+			if (!f(g, sub, extra))					\
+				return false;						\
+		}											\
+		break;										\
+	case TYPE_TUPLE:								\
+		arr_foreach(type->tuple, Type, sub)			\
+			if (!f(g, sub, extra))					\
+				return false;						\
+		break;										\
+	case TYPE_ARR:									\
+		if (!f(g, type->arr.of, extra))				\
+			return false;							\
+		break;										\
+	case TYPE_SLICE:								\
+		if (!f(g, type->slice, extra))				\
+			return false;							\
+		break;										\
+	case TYPE_PTR:									\
+		if (!f(g, type->ptr, extra))				\
+			return false;							\
+		break;										\
+	case TYPE_VOID:									\
+	case TYPE_BUILTIN:								\
+	case TYPE_PKG:									\
+	case TYPE_TYPE:									\
+	case TYPE_UNKNOWN:								\
+		break;										\
+	case TYPE_EXPR: assert(0);						\
+	}
+
+
+/* i is the name for this type, NULL if not available */
+/* ALWAYS RETURNS TRUE. it just returns a bool for cgen_recurse_into_type to work */
+static bool typedefs_type(CGenerator *g, Type *type, Identifier i) {
+	if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
+		return true;
+	if (type->kind == TYPE_STRUCT) {
+		StructDef *sdef = type->struc;
+		/* we'll actually define the struct later; here we can just declare it */
+	
+		if (sdef->c.id || sdef->c.name) {
+			/* we've already done this */
+		} else {
+			cgen_write(g, "struct ");
+			if (i) {
+				cgen_ident(g, i);
+				sdef->c.name = i;
+			} else {
+				IdentID id = ++g->ident_counter;
+				cgen_ident_id(g, id);
+				sdef->c.id = id;
+			}
+			cgen_write(g, ";");
+			cgen_nl(g);
+		}
+	}
+	cgen_recurse_into_type(typedefs_type, g, type, NULL);
+	return true;
+}
+
 static bool typedefs_block(CGenerator *g, Block *b) {
 	Block *prev = g->block;
 	if (!cgen_block_enter(g, b))
@@ -22,9 +91,12 @@ static bool typedefs_block(CGenerator *g, Block *b) {
 
 static bool typedefs_expr(CGenerator *g, Expression *e) {
 	cgen_recurse_subexprs(g, e, typedefs_expr, typedefs_block, typedefs_decl);
+	if (e->kind == EXPR_CAST) {
+		typedefs_type(g, &e->cast.type, NULL);
+	}
 	if (e->kind == EXPR_FN) {
 		/* needs to go before decls_cgen.c... */
-		e->fn->c.id = g->ident_counter++;
+		e->fn->c.id = ++g->ident_counter;
 	}
 	if (e->kind == EXPR_TYPE && e->typeval.kind == TYPE_STRUCT) {
 		StructDef *sdef = e->typeval.struc;
@@ -32,7 +104,7 @@ static bool typedefs_expr(CGenerator *g, Expression *e) {
 			/* we've already done this */
 		} else {
 			cgen_write(g, "struct ");
-			IdentID id = g->ident_counter++;
+			IdentID id = ++g->ident_counter;
 			cgen_ident_id(g, id);
 			sdef->c.id = id;
 			cgen_write(g, ";");
@@ -43,6 +115,7 @@ static bool typedefs_expr(CGenerator *g, Expression *e) {
 }
 
 static bool typedefs_decl(CGenerator *g, Declaration *d) {
+	typedefs_type(g, &d->type, NULL);
 	if (cgen_fn_is_direct(g, d)) {
 		d->expr.fn->c.name = d->idents[0];
 	}
@@ -52,26 +125,12 @@ static bool typedefs_decl(CGenerator *g, Declaration *d) {
 		Value *val = decl_val_at_index(d, idx);
 		if (type->kind == TYPE_TYPE) {
 			/* generate typedef */
-			IdentID id = 0;
-			if (g->block != NULL || g->fn != NULL)
-				id = g->ident_counter++;
-			if (val->type->kind == TYPE_STRUCT) {
-				/* we'll actually define the struct later; here we can just declare it */
-				StructDef *sdef = val->type->struc;
-				if (sdef->c.id || sdef->c.name) {
-					/* we've already done this */
-				} else {
-					cgen_write(g, "struct ");
-					if (id) {
-						cgen_ident_id(g, id);
-						sdef->c.id = id;
-					} else {
-						cgen_ident(g, i);
-						sdef->c.name = i;
-					}
-					cgen_write(g, ";");
-				}
-			} else {
+			typedefs_type(g, val->type, i);
+			
+			if (val->type->kind != TYPE_STRUCT) {
+				IdentID id = 0;
+				if (g->block != NULL || g->fn != NULL)
+					id = ++g->ident_counter;
 				if (val->type->kind != TYPE_TYPE) {
 					cgen_write(g, "typedef ");
 					if (!cgen_type_pre(g, val->type, d->where)) return false;
diff --git a/types.c b/types.c
index 143dbec..66a31e9 100644
--- a/types.c
+++ b/types.c
@@ -7,6 +7,7 @@ static bool types_stmt(Typer *tr, Statement *s);
 static bool types_block(Typer *tr, Block *b);
 static bool type_resolve(Typer *tr, Type *t, Location where);
 
+
 static inline void *typer_malloc(Typer *tr, size_t bytes) {
 	return allocr_malloc(tr->allocr, bytes);
 }
@@ -23,6 +24,10 @@ static inline bool type_is_builtin(Type *t, BuiltinType b) {
 	return t->kind == TYPE_BUILTIN && t->builtin == b;
 }
 
+static inline bool type_is_slicechar(Type *t) {
+	return t->kind == TYPE_SLICE && type_is_builtin(t->slice, BUILTIN_CHAR);
+}
+
 #define typer_arr_add(tr, a) typer_arr_add_(tr, (void **)(a), sizeof **(a))
 
 static bool type_eq(Type *a, Type *b) {
@@ -826,7 +831,7 @@ static bool types_expr(Typer *tr, Expression *e) {
 	case EXPR_LITERAL_INT:
 	    t->kind = TYPE_BUILTIN;
 		t->builtin = BUILTIN_I64;
-		t->flags |= TYPE_IS_FLEXIBLE | TYPE_IS_RESOLVED;
+		t->flags |= TYPE_IS_FLEXIBLE;
 		break;
 	case EXPR_LITERAL_STR:
 		t->kind = TYPE_SLICE;
@@ -835,22 +840,25 @@ static bool types_expr(Typer *tr, Expression *e) {
 		t->slice->was_expr = NULL;
 		t->slice->kind = TYPE_BUILTIN;
 		t->slice->builtin = BUILTIN_CHAR;
-		t->flags |= TYPE_IS_RESOLVED;
 		break;
 	case EXPR_LITERAL_FLOAT:
 		t->kind = TYPE_BUILTIN;
 		t->builtin = BUILTIN_F32;
-		t->flags |= TYPE_IS_FLEXIBLE | TYPE_IS_RESOLVED;
+		t->flags |= TYPE_IS_FLEXIBLE;
 		break;
 	case EXPR_LITERAL_BOOL:
 		t->kind = TYPE_BUILTIN;
 		t->builtin = BUILTIN_BOOL;
-		t->flags |= TYPE_IS_RESOLVED;
 		break;
 	case EXPR_LITERAL_CHAR:
 		t->kind = TYPE_BUILTIN;
 		t->builtin = BUILTIN_CHAR;
-		t->flags |= TYPE_IS_RESOLVED;
+		break;
+	case EXPR_PKG:
+		t->kind = TYPE_PKG;
+		Expression *name_expr = e->pkg.name_expr;
+		if (!types_expr(tr, name_expr)) return false;
+		Value name_val;
 		break;
 	case EXPR_EACH: {
 		EachExpr *ea = e->each;
@@ -1476,10 +1484,9 @@ static bool types_expr(Typer *tr, Expression *e) {
 		Expression *code = e->c.code;
 		if (!types_expr(tr, code))
 			return false;
-		if (code->type.kind != TYPE_SLICE
-			|| !type_is_builtin(code->type.slice, BUILTIN_CHAR)) {
+		if (!type_is_slicechar(&code->type)) {
 			char *s = type_to_str(&code->type);
-			err_print(e->where, "Argument to #C directive must be a string, but got type %s.");
+			err_print(e->where, "Argument to #C directive must of type []char, but got type %s.");
 			free(s);
 			return false;
 		}
@@ -1732,8 +1739,7 @@ static bool types_expr(Typer *tr, Expression *e) {
 				/* fallthrough */
 			case TYPE_STRUCT: {
 				/* allow accessing struct members with a string */
-				if (rhs_type->kind != TYPE_SLICE
-					|| !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) {
+				if (!type_is_slicechar(rhs_type)) {
 					char *s = type_to_str(rhs_type);
 					err_print(e->where, "Expected a string for struct member access with [], but got type %s.", s);
 					return false;
@@ -1803,10 +1809,11 @@ static bool types_expr(Typer *tr, Expression *e) {
 						
 					Value field_name;
 					if (!types_expr(tr, rhs)) return false;
-					if (rhs_type->kind != TYPE_SLICE || !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) {
-						err_print(e->where, "Invalid field of type %s.");
+					if (!type_is_slicechar(rhs_type)) {
+						char *s = type_to_str(rhs_type);
+						err_print(e->where, "Invalid field of type %s.", s);
+						free(s);
 						return false;
-						
 					}
 					if (!eval_expr(tr->evalr, rhs, &field_name)) return false;
 					char *str = field_name.slice.data;
@@ -2125,7 +2132,7 @@ static bool types_file(Typer *tr, ParsedFile *f, char *code) {
 		Value pkg_name;
 		if (!types_expr(tr, f->pkg_name))
 			return false;
-		if (f->pkg_name->type.kind != TYPE_SLICE || !type_is_builtin(f->pkg_name->type.slice, BUILTIN_CHAR)) {
+		if (!type_is_slicechar(&f->pkg_name->type)) {
 			char *typestr = type_to_str(&f->pkg_name->type);
 			err_print(f->pkg_name->where, "Package names must be of type []char, but this is of type %s.", typestr);
 			free(typestr);
diff --git a/types.h b/types.h
index 147ee44..dc0d817 100644
--- a/types.h
+++ b/types.h
@@ -150,6 +150,7 @@ typedef union Value {
 	union Value *tuple;
 	Slice slice;
 	struct Type *type;
+	struct Package *pkg;
 } Value;
 
 enum {
@@ -187,6 +188,7 @@ typedef struct IdentTree {
 	unsigned char index_in_parent; /* index of this in .parent.children */
 	bool export_name; /* is this identifier's name important? */
 	U64 export_id; /* 0 if there's no exported identifier here, otherwise unique positive integer associated with this identifier */
+	struct Package *pkg; /* NULL if this is not associated with a package */
 	struct IdentTree *parent;
 	struct IdentTree *children[TREE_NCHILDREN];
 	IdentDecl *decls; /* array of declarations of this identifier */
@@ -643,8 +645,9 @@ typedef struct Expression {
 		struct {
 			Type type;
 		} del;
-		struct {
-			struct Expression *name;
+		union {
+			struct Expression *name_expr;
+			Identifier name_ident;
 		} pkg;
 		IfExpr if_;
 		WhileExpr while_;
@@ -763,6 +766,10 @@ typedef struct Typer {
 	char *pkg_name;
 } Typer;
 
+typedef struct Package {
+	Identifier name;
+	Identifiers idents;
+} Package;
 
 typedef struct Exporter {
 	FILE *out; /* .top (toc package) to output to */
@@ -790,6 +797,7 @@ typedef struct CGenerator {
 	Identifiers *idents;
 } CGenerator;
 
+
 #ifdef TOC_DEBUG
 #define add_ident_decls(b, d, flags) add_ident_decls_(__FILE__, __LINE__, b, d, flags)
 #endif
-- 
cgit v1.2.3