Browse Source

Move cycle checking to much earlier on in the semantic stage

gingerBill 7 years ago
parent
commit
30f5a3bb93
10 changed files with 259 additions and 177 deletions
  1. 7 2
      src/check_decl.cpp
  2. 29 4
      src/check_expr.cpp
  3. 10 10
      src/check_stmt.cpp
  4. 48 38
      src/check_type.cpp
  5. 68 36
      src/checker.cpp
  6. 11 2
      src/checker.hpp
  7. 38 38
      src/entity.cpp
  8. 32 42
      src/ir.cpp
  9. 2 0
      src/main.cpp
  10. 14 5
      src/types.cpp

+ 7 - 2
src/check_decl.cpp

@@ -227,6 +227,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
 		error(decl->attributes[0], "Attributes are not allowed on type declarations");
 	}
 
+
+
 	bool is_distinct = is_type_distinct(type_expr);
 	AstNode *te = remove_type_alias_clutter(type_expr);
 	e->type = t_invalid;
@@ -238,7 +240,10 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
 	}
 	e->type = named;
 
-	Type *bt = check_type(c, te, named);
+	check_type_path_push(c, e);
+	Type *bt = check_type_expr(c, te, named);
+	check_type_path_pop(c);
+
 	named->Named.base = base_type(bt);
 	if (!is_distinct) {
 		e->type = bt;
@@ -985,7 +990,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
 				for_array(i, scope->elements.entries) {
 					Entity *f = scope->elements.entries[i].value;
 					if (f->kind == Entity_Variable) {
-						Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+						Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
 						uvar->Variable.is_immutable = is_immutable;
 						if (is_value) uvar->flags |= EntityFlag_Value;
 

+ 29 - 4
src/check_expr.cpp

@@ -55,7 +55,8 @@ void     check_multi_expr               (Checker *c, Operand *operand, AstNode *
 void     check_expr_or_type             (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = nullptr);
 ExprKind check_expr_base                (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
 void     check_expr_with_type_hint      (Checker *c, Operand *o, AstNode *e, Type *t);
-Type *   check_type                     (Checker *c, AstNode *expression, Type *named_type = nullptr);
+Type *   check_type                     (Checker *c, AstNode *expression);
+Type *   check_type_expr                (Checker *c, AstNode *expression, Type *named_type);
 Type *   make_optional_ok_type          (Type *value);
 void     check_type_decl                (Checker *c, Entity *e, AstNode *type_expr, Type *def);
 Entity * check_selector                 (Checker *c, Operand *operand, AstNode *node, Type *type_hint);
@@ -334,7 +335,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
 	d->proc_lit = proc_lit;
 
 
-	Entity *entity = make_entity_procedure(c->allocator, nullptr, token, final_proc_type, tags);
+	Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
 	entity->identifier = ident;
 
 	add_entity_and_decl_info(c, ident, entity, d);
@@ -903,6 +904,27 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
 	return false;
 }
 
+bool check_cycle(Checker *c, Entity *curr, bool report) {
+	if (curr->state != EntityState_InProgress) {
+		return false;
+	}
+	for_array(i, *c->context.type_path) {
+		Entity *prev = (*c->context.type_path)[i];
+		if (prev == curr) {
+			if (report) {
+				error(curr->token, "Illegal declaration cycle of `%.*s`", LIT(curr->token.string));
+				for (isize j = i; j < c->context.type_path->count; j++) {
+					Entity *curr = (*c->context.type_path)[j];
+					error(curr->token, "\t%.*s refers to", LIT(curr->token.string));
+				}
+				error(curr->token, "\t%.*s", LIT(curr->token.string));
+			}
+			return true;
+		}
+	}
+	return false;
+}
+
 
 Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
 	GB_ASSERT(n->kind == AstNode_Ident);
@@ -1036,6 +1058,9 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
 
 	case Entity_TypeName:
 		o->mode = Addressing_Type;
+		if (check_cycle(c, e, true)) {
+			type = t_invalid;
+		}
 		break;
 
 	case Entity_ImportName:
@@ -3152,8 +3177,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		Type *proc_type_params = alloc_type_tuple(c->allocator);
 		proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
 		proc_type_params->Tuple.variable_count = 2;
-		proc_type_params->Tuple.variables[0] = make_entity_param(c->allocator, nullptr, blank_token, operand->type, false, false);
-		proc_type_params->Tuple.variables[1] = make_entity_param(c->allocator, nullptr, blank_token, slice_elem, false, false);
+		proc_type_params->Tuple.variables[0] = alloc_entity_param(c->allocator, nullptr, blank_token, operand->type, false, false);
+		proc_type_params->Tuple.variables[1] = alloc_entity_param(c->allocator, nullptr, blank_token, slice_elem, false, false);
 		Type *proc_type = alloc_type_proc(nullptr, proc_type_params, 2, nullptr, false, true, ProcCC_Odin);
 
 		check_call_arguments(c, &prev_operand, proc_type, call);

+ 10 - 10
src/check_stmt.cpp

@@ -431,7 +431,7 @@ void check_label(Checker *c, AstNode *label) {
 		}
 	}
 
-	Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident.token, t_invalid, label);
+	Entity *e = alloc_entity_label(c->context.scope, l->name->Ident.token, t_invalid, label);
 	add_entity(c, c->context.scope, l->name, e);
 	e->parent_proc_decl = c->context.curr_proc_decl;
 
@@ -507,7 +507,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
 			for_array(i, found->elements.entries) {
 				Entity *f = found->elements.entries[i].value;
 				if (f->kind == Entity_Variable) {
-					Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
 					uvar->using_expr = expr;
 					Entity *prev = scope_insert_entity(c->context.scope, uvar);
 					if (prev != nullptr) {
@@ -1000,7 +1000,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
 
 		check_open_scope(c, stmt);
 		{
-			Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident.token, case_type, false, EntityState_Resolved);
+			Entity *tag_var = alloc_entity_variable(c->context.scope, lhs->Ident.token, case_type, false, EntityState_Resolved);
 			tag_var->flags |= EntityFlag_Used;
 			tag_var->flags |= EntityFlag_Value;
 			add_entity(c, c->context.scope, lhs, tag_var);
@@ -1467,7 +1467,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 				}
 				if (found == nullptr) {
 					bool is_immutable = true;
-					entity = make_entity_variable(c->allocator, c->context.scope, token, type, is_immutable, EntityState_Resolved);
+					entity = alloc_entity_variable(c->context.scope, token, type, is_immutable, EntityState_Resolved);
 					add_entity_definition(&c->info, name, entity);
 				} else {
 					TokenPos pos = found->token.pos;
@@ -1482,7 +1482,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 			}
 
 			if (entity == nullptr) {
-				entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
+				entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name));
 			}
 
 			entities[entity_count++] = entity;
@@ -1700,7 +1700,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 						continue;
 					}
 
-					Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+					Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
 					uvar->using_expr = expr;
 					Entity *prev = scope_insert_entity(c->context.scope, uvar);
 					if (prev != nullptr) {
@@ -1797,7 +1797,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 						new_name_count += 1;
 					}
 					if (found == nullptr) {
-						entity = make_entity_variable(c->allocator, c->context.scope, token, nullptr, false);
+						entity = alloc_entity_variable(c->context.scope, token, nullptr, false);
 						entity->identifier = name;
 
 						AstNode *fl = c->context.foreign_context.curr_library;
@@ -1816,7 +1816,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					}
 				}
 				if (entity == nullptr) {
-					entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
+					entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name));
 				}
 				entity->parent_proc_decl = c->context.curr_proc_decl;
 				entities[entity_count++] = entity;
@@ -1828,7 +1828,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 
 			Type *init_type = nullptr;
 			if (vd->type != nullptr) {
-				init_type = check_type(c, vd->type, nullptr);
+				init_type = check_type(c, vd->type);
 				if (init_type == nullptr) {
 					init_type = t_invalid;
 				} else if (is_type_polymorphic(base_type(init_type))) {
@@ -1938,7 +1938,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 						for_array(i, scope->elements.entries) {
 							Entity *f = scope->elements.entries[i].value;
 							if (f->kind == Entity_Variable) {
-								Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
+								Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
 								uvar->Variable.is_immutable = is_immutable;
 								Entity *prev = scope_insert_entity(c->context.scope, uvar);
 								if (prev != nullptr) {

+ 48 - 38
src/check_type.cpp

@@ -111,7 +111,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
 				gb_printf_err("Element\n");
 			}
 
-			type = check_type(c, type_expr);
+			type = check_type_expr(c, type_expr, nullptr);
 
 			if (default_value != nullptr) {
 				Operand o = {};
@@ -179,7 +179,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
 			Token name_token = name->Ident.token;
 
 			Entity *field = nullptr;
-			field = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, field_src_index);
+			field = alloc_entity_field(c->context.scope, name_token, type, is_using, field_src_index);
 			field->Variable.default_value = value;
 			field->Variable.default_is_nil = default_is_nil;
 
@@ -211,8 +211,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
 
 
 Entity *make_names_field_for_struct(Checker *c, Scope *scope) {
-	Entity *e = make_entity_field(c->allocator, scope,
-		make_token_ident(str_lit("names")), t_string_slice, false, 0);
+	Entity *e = alloc_entity_field(scope, make_token_ident(str_lit("names")), t_string_slice, false, 0);
 	e->Variable.is_immutable = true;
 	e->flags |= EntityFlag_TypeField;
 	return e;
@@ -311,7 +310,7 @@ void add_polymorphic_struct_entity(Checker *c, AstNode *node, Type *named_type,
 		node->kind = AstNode_Ident;
 		node->Ident.token = token;
 
-		e = make_entity_type_name(a, s, token, named_type);
+		e = alloc_entity_type_name(s, token, named_type);
 		e->state = EntityState_Resolved;
 		add_entity_use(c, node, e);
 	}
@@ -454,18 +453,18 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
 								is_polymorphic = true;
 								can_check_fields = false;
 							}
-							e = make_entity_type_name(c->allocator, scope, token, operand.type);
+							e = alloc_entity_type_name(scope, token, operand.type);
 							e->TypeName.is_type_alias = true;
 						} else {
 							GB_ASSERT(operand.mode == Addressing_Constant);
-							e = make_entity_constant(c->allocator, scope, token, operand.type, operand.value);
+							e = alloc_entity_constant(scope, token, operand.type, operand.value);
 						}
 					} else {
 						if (is_type_param) {
-							e = make_entity_type_name(c->allocator, scope, token, type);
+							e = alloc_entity_type_name(scope, token, type);
 							e->TypeName.is_type_alias = true;
 						} else {
-							e = make_entity_constant(c->allocator, scope, token, type, empty_exact_value);
+							e = alloc_entity_constant(scope, token, type, empty_exact_value);
 						}
 					}
 
@@ -551,7 +550,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
 
 	for_array(i, ut->variants) {
 		AstNode *node = ut->variants[i];
-		Type *t = check_type(c, node);
+		Type *t = check_type_expr(c, node, nullptr);
 		if (t != nullptr && t != t_invalid) {
 			bool ok = true;
 			t = default_type(t);
@@ -697,7 +696,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 			max_value = iota;
 		}
 
-		Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident.token, constant_type, iota);
+		Entity *e = alloc_entity_constant(c->context.scope, ident->Ident.token, constant_type, iota);
 		e->identifier = ident;
 		e->flags |= EntityFlag_Visited;
 		e->state = EntityState_Resolved;
@@ -732,12 +731,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 		}
 	}
 
-	enum_type->Enum.count = make_entity_constant(c->allocator, c->context.scope,
-		make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
-	enum_type->Enum.min_value = make_entity_constant(c->allocator, c->context.scope,
-		make_token_ident(str_lit("min_value")), constant_type, min_value);
-	enum_type->Enum.max_value = make_entity_constant(c->allocator, c->context.scope,
-		make_token_ident(str_lit("max_value")), constant_type, max_value);
+	Scope *s = c->context.scope;
+	enum_type->Enum.count     = alloc_entity_constant(s, make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
+	enum_type->Enum.min_value = alloc_entity_constant(s, make_token_ident(str_lit("min_value")), constant_type, min_value);
+	enum_type->Enum.max_value = alloc_entity_constant(s, make_token_ident(str_lit("max_value")), constant_type, max_value);
 
 	enum_type->Enum.names = make_names_field_for_struct(c, c->context.scope);
 }
@@ -789,7 +786,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
 		u32 bits = cast(u32)bits_;
 
 		Type *value_type = alloc_type_bit_field_value(bits);
-		Entity *e = make_entity_variable(c->allocator, bit_field_type->BitField.scope, ident->Ident.token, value_type, false);
+		Entity *e = alloc_entity_variable(bit_field_type->BitField.scope, ident->Ident.token, value_type, false);
 		e->identifier = ident;
 		e->flags |= EntityFlag_BitFieldValue;
 
@@ -1184,7 +1181,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 						type = t_invalid;
 					}
 				}
-				param = make_entity_type_name(c->allocator, scope, name->Ident.token, type, EntityState_Resolved);
+				param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
 				param->TypeName.is_type_alias = true;
 			} else {
 				if (operands != nullptr && variables.count < operands->count) {
@@ -1207,7 +1204,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 					}
 				}
 
-				param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, is_in);
+				param = alloc_entity_param(scope, name->Ident.token, type, is_using, is_in);
 				param->Variable.default_value = value;
 				param->Variable.default_is_nil = default_is_nil;
 				param->Variable.default_is_location = default_is_location;
@@ -1336,7 +1333,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 		if (field->names.count == 0) {
 			Token token = ast_node_token(field->type);
 			token.string = str_lit("");
-			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+			Entity *param = alloc_entity_param(scope, token, type, false, false);
 			param->Variable.default_value = value;
 			param->Variable.default_is_nil = default_is_nil;
 			array_add(&variables, param);
@@ -1359,7 +1356,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
 					error(name, "Result value cannot be a blank identifer `_`");
 				}
 
-				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+				Entity *param = alloc_entity_param(scope, token, type, false, false);
 				param->flags |= EntityFlag_Result;
 				param->Variable.default_value = value;
 				param->Variable.default_is_nil = default_is_nil;
@@ -1542,7 +1539,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
 	if (new_type != original_type) {
 		Type *tuple = alloc_type_tuple();
 		auto variables = array_make<Entity *>(a, 0, 1);
-		array_add(&variables, make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false));
+		array_add(&variables, alloc_entity_param(original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false));
 		tuple->Tuple.variables = variables;
 		new_type = tuple;
 	}
@@ -1732,8 +1729,8 @@ Type *make_optional_ok_type(Type *value) {
 	bool typed = true;
 	Type *t = alloc_type_tuple();
 	array_init(&t->Tuple.variables, a, 0, 2);
-	array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, value,  false, 0));
-	array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1));
+	array_add (&t->Tuple.variables, alloc_entity_field(nullptr, blank_token, value,  false, 0));
+	array_add (&t->Tuple.variables, alloc_entity_field(nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1));
 	return t;
 }
 
@@ -1759,9 +1756,9 @@ void init_map_entry_type(Type *type) {
 	Scope *s = create_scope(universal_scope, a);
 
 	auto fields = array_make<Entity *>(a, 0, 3);
-	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("key")),   t_map_key,       false, 0, EntityState_Resolved));
-	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("next")),  t_int,           false, 1, EntityState_Resolved));
-	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved));
+	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")),   t_map_key,       false, 0, EntityState_Resolved));
+	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")),  t_int,           false, 1, EntityState_Resolved));
+	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved));
 
 
 	entry_type->Struct.fields = fields;
@@ -1799,8 +1796,8 @@ void init_map_internal_types(Type *type) {
 
 
 	auto fields = array_make<Entity *>(a, 0, 2);
-	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0, EntityState_Resolved));
-	array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
+	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hashes")),  hashes_type,  false, 0, EntityState_Resolved));
+	array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
 
 	generated_struct_type->Struct.fields = fields;
 
@@ -1837,6 +1834,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
 	// error(node, "'map' types are not yet implemented");
 }
 
+
+
 bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) {
 	GB_ASSERT_NOT_NULL(type);
 	if (e == nullptr) {
@@ -1846,7 +1845,6 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 
 	switch (e->kind) {
 	case_ast_node(i, Ident, e);
-
 		Operand o = {};
 		Entity *entity = check_ident(c, &o, e, named_type, nullptr, false);
 
@@ -1867,9 +1865,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 				}
 			}
 
-			if (c->context.type_level == 0 && entity->state == EntityState_InProgress) {
-				error(e, "Illegal declaration cycle of `%.*s`", LIT(entity->token.string));
-			}
+			// if (c->context.type_level == 0 && entity->state == EntityState_InProgress) {
+			// 	error(entity->token, "Illegal declaration cycle of `%.*s`", LIT(entity->token.string));
+			// 	for_array(j, *c->context.type_path) {
+			// 		Entity *k = (*c->context.type_path)[j];
+			// 		error(k->token, "\t%.*s refers to", LIT(k->token.string));
+			// 	}
+			// 	error(entity->token, "\t%.*s", LIT(entity->token.string));
+			// 	*type = t_invalid;
+			// }
 			return true;
 		}
 
@@ -1927,7 +1931,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 				GB_ASSERT(is_scope_an_ancestor(ps, s) >= 0);
 				entity_scope = ps;
 			}
-			Entity *e = make_entity_type_name(c->allocator, entity_scope, token, t);
+			Entity *e = alloc_entity_type_name(entity_scope, token, t);
 			e->TypeName.is_type_alias = true;
 			e->state = EntityState_Resolved;
 			add_entity(c, ps, ident, e);
@@ -1968,7 +1972,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 	case_end;
 
 	case_ast_node(pe, ParenExpr, e);
-		*type = check_type(c, pe->expr, named_type);
+		*type = check_type_expr(c, pe->expr, named_type);
 		set_base_type(named_type, *type);
 		return true;
 	case_end;
@@ -2000,7 +2004,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 				error(at->count, "... can only be used in conjuction with compound literals");
 				count = 0;
 			}
-			Type *elem = check_type(c, at->elem, nullptr);
+			Type *elem = check_type_expr(c, at->elem, nullptr);
 			*type = alloc_type_array(elem, count, generic_type);
 		} else {
 			Type *elem = check_type(c, at->elem);
@@ -2117,9 +2121,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 	return false;
 }
 
+Type *check_type(Checker *c, AstNode *e) {
+	auto prev_context = c->context; defer (c->context = prev_context);
+	c->context.type_path = new_checker_type_path();
+	defer (destroy_checker_type_path(c->context.type_path));
 
+	return check_type_expr(c, e, nullptr);
+}
 
-Type *check_type(Checker *c, AstNode *e, Type *named_type) {
+Type *check_type_expr(Checker *c, AstNode *e, Type *named_type) {
 	Type *type = nullptr;
 	bool ok = check_type_internal(c, e, &type, named_type);
 

+ 68 - 36
src/checker.cpp

@@ -507,20 +507,20 @@ Entity *add_global_entity(Entity *entity) {
 	return entity;
 }
 
-void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
-	Entity *entity = alloc_entity(a, Entity_Constant, nullptr, make_token_ident(name), type);
+void add_global_constant(String name, Type *type, ExactValue value) {
+	Entity *entity = alloc_entity(Entity_Constant, nullptr, make_token_ident(name), type);
 	entity->Constant.value = value;
 	add_global_entity(entity);
 }
 
 
-void add_global_string_constant(gbAllocator a, String name, String value) {
-	add_global_constant(a, name, t_untyped_string, exact_value_string(value));
+void add_global_string_constant(String name, String value) {
+	add_global_constant(name, t_untyped_string, exact_value_string(value));
 }
 
 
-void add_global_type_entity(gbAllocator a, String name, Type *type) {
-	add_global_entity(make_entity_type_name(a, nullptr, make_token_ident(name), type));
+void add_global_type_entity(String name, Type *type) {
+	add_global_entity(alloc_entity_type_name(nullptr, make_token_ident(name), type));
 }
 
 
@@ -533,27 +533,27 @@ void init_universal_scope(void) {
 
 // Types
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
-		add_global_type_entity(a, basic_types[i].Basic.name, &basic_types[i]);
+		add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]);
 	}
-	add_global_type_entity(a, str_lit("byte"), &basic_types[Basic_u8]);
+	add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
 
 // Constants
-	add_global_constant(a, str_lit("true"),  t_untyped_bool, exact_value_bool(true));
-	add_global_constant(a, str_lit("false"), t_untyped_bool, exact_value_bool(false));
+	add_global_constant(str_lit("true"),  t_untyped_bool, exact_value_bool(true));
+	add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false));
 
-	add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
-	add_global_entity(make_entity_library_name(a,  universal_scope,
-	                                           make_token_ident(str_lit("__llvm_core")), t_invalid,
-	                                           str_lit(""), str_lit("__llvm_core")));
+	add_global_entity(alloc_entity_nil(str_lit("nil"), t_untyped_nil));
+	add_global_entity(alloc_entity_library_name(universal_scope,
+	                                            make_token_ident(str_lit("__llvm_core")), t_invalid,
+	                                            str_lit(""), str_lit("__llvm_core")));
 
 	// TODO(bill): Set through flags in the compiler
-	add_global_string_constant(a, str_lit("ODIN_OS"),      bc->ODIN_OS);
-	add_global_string_constant(a, str_lit("ODIN_ARCH"),    bc->ODIN_ARCH);
-	add_global_string_constant(a, str_lit("ODIN_ENDIAN"),  bc->ODIN_ENDIAN);
-	add_global_string_constant(a, str_lit("ODIN_VENDOR"),  bc->ODIN_VENDOR);
-	add_global_string_constant(a, str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
-	add_global_string_constant(a, str_lit("ODIN_ROOT"),    bc->ODIN_ROOT);
-	add_global_constant(a, str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG));
+	add_global_string_constant(str_lit("ODIN_OS"),      bc->ODIN_OS);
+	add_global_string_constant(str_lit("ODIN_ARCH"),    bc->ODIN_ARCH);
+	add_global_string_constant(str_lit("ODIN_ENDIAN"),  bc->ODIN_ENDIAN);
+	add_global_string_constant(str_lit("ODIN_VENDOR"),  bc->ODIN_VENDOR);
+	add_global_string_constant(str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
+	add_global_string_constant(str_lit("ODIN_ROOT"),    bc->ODIN_ROOT);
+	add_global_constant(str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG));
 
 
 // Builtin Procedures
@@ -561,7 +561,7 @@ void init_universal_scope(void) {
 		BuiltinProcId id = cast(BuiltinProcId)i;
 		String name = builtin_procs[i].name;
 		if (name != "") {
-			Entity *entity = alloc_entity(a, Entity_Builtin, nullptr, make_token_ident(name), t_invalid);
+			Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid);
 			entity->Builtin.id = id;
 			add_global_entity(entity);
 		}
@@ -639,12 +639,17 @@ void init_checker(Checker *c, Parser *parser) {
 	c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
 
 	c->global_scope = create_scope(universal_scope, c->allocator);
-	c->context.scope = c->global_scope;
 
 	map_init(&c->file_scopes, heap_allocator());
 	ptr_set_init(&c->checked_files, heap_allocator());
 
 	array_init(&c->file_order, heap_allocator(), 0, c->parser->files.count);
+
+	// Init context
+	c->context.scope = c->global_scope;
+
+	c->context.type_path = new_checker_type_path();
+	c->context.type_level = 0;
 }
 
 void destroy_checker(Checker *c) {
@@ -660,6 +665,8 @@ void destroy_checker(Checker *c) {
 	map_destroy(&c->file_scopes);
 	ptr_set_destroy(&c->checked_files);
 	array_free(&c->file_order);
+
+	destroy_checker_type_path(c->context.type_path);
 }
 
 
@@ -1312,6 +1319,31 @@ Type *find_core_type(Checker *c, String name) {
 	return e->type;
 }
 
+CheckerTypePath *new_checker_type_path() {
+	gbAllocator a = heap_allocator();
+	auto *tp = gb_alloc_item(a, CheckerTypePath);
+	array_init(tp, a, 0, 16);
+	return tp;
+}
+
+void destroy_checker_type_path(CheckerTypePath *tp) {
+	array_free(tp);
+	gb_free(heap_allocator(), tp);
+}
+
+
+void check_type_path_push(Checker *c, Entity *e) {
+	GB_ASSERT(c->context.type_path != nullptr);
+	GB_ASSERT(e != nullptr);
+	array_add(c->context.type_path, e);
+}
+Entity *check_type_path_pop(Checker *c) {
+	GB_ASSERT(c->context.type_path != nullptr);
+	return array_pop(c->context.type_path);
+}
+
+
+
 
 void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type);
 
@@ -1424,9 +1456,9 @@ void init_preload(Checker *c) {
 		Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
 		Scope *preload_scope = type_info_entity->scope;
 
-		Entity *e = make_entity_import_name(c->allocator, preload_scope, make_token_ident(_global), t_invalid,
-		                                    str_lit(""), _global,
-		                                    preload_scope);
+		Entity *e = alloc_entity_import_name(preload_scope, make_token_ident(_global), t_invalid,
+		                                     str_lit(""), _global,
+		                                     preload_scope);
 
 		add_entity(c, universal_scope, nullptr, e);
 	}
@@ -1745,7 +1777,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
 				error(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
 				continue;
 			}
-			Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident.token, nullptr, false);
+			Entity *e = alloc_entity_variable(c->context.scope, name->Ident.token, nullptr, false);
 			e->identifier = name;
 
 			if (vd->is_using) {
@@ -1808,7 +1840,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
 
 			if (is_ast_node_type(init) ||
 				(vd->type != nullptr && vd->type->kind == AstNode_TypeType)) {
-				e = make_entity_type_name(c->allocator, d->scope, token, nullptr);
+				e = alloc_entity_type_name(d->scope, token, nullptr);
 				if (vd->type != nullptr) {
 					error(name, "A type declaration cannot have an type parameter");
 				}
@@ -1820,7 +1852,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
 					continue;
 				}
 				ast_node(pl, ProcLit, init);
-				e = make_entity_procedure(c->allocator, d->scope, token, nullptr, pl->tags);
+				e = alloc_entity_procedure(d->scope, token, nullptr, pl->tags);
 				if (fl != nullptr) {
 					GB_ASSERT(fl->kind == AstNode_Ident);
 					e->Procedure.foreign_library_ident = fl;
@@ -1846,13 +1878,13 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
 				d->type_expr = pl->type;
 			} else if (init->kind == AstNode_ProcGroup) {
 				ast_node(pg, ProcGroup, init);
-				e = make_entity_proc_group(c->allocator, d->scope, token, nullptr);
+				e = alloc_entity_proc_group(d->scope, token, nullptr);
 				if (fl != nullptr) {
 					error(name, "Procedure groups are not allowed within a foreign block");
 				}
 				d->init_expr = init;
 			} else {
-				e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
+				e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
 				d->type_expr = vd->type;
 				d->init_expr = init;
 			}
@@ -2340,9 +2372,9 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
 		} else {
 			GB_ASSERT(id->import_name.pos.line != 0);
 			id->import_name.string = import_name;
-			Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
-			                                    id->fullpath, id->import_name.string,
-			                                    scope);
+			Entity *e = alloc_entity_import_name(parent_scope, id->import_name, t_invalid,
+			                                     id->fullpath, id->import_name.string,
+			                                     scope);
 
 			add_entity(c, parent_scope, nullptr, e);
 		}
@@ -2524,8 +2556,8 @@ void check_add_foreign_import_decl(Checker *c, AstNode *decl) {
 
 	GB_ASSERT(fl->library_name.pos.line != 0);
 	fl->library_name.string = library_name;
-	Entity *e = make_entity_library_name(c->allocator, parent_scope, fl->library_name, t_invalid,
-	                                     fl->fullpath, library_name);
+	Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
+	                                      fl->fullpath, library_name);
 	add_entity(c, parent_scope, nullptr, e);
 }
 

+ 11 - 2
src/checker.hpp

@@ -262,19 +262,23 @@ struct ForeignContext {
 	bool                  in_export;
 };
 
+typedef Array<Entity *> CheckerTypePath;
+
 struct CheckerContext {
 	Scope *    file_scope;
 	Scope *    scope;
 	DeclInfo * decl;
 	u32        stmt_state_flags;
 	bool       in_defer; // TODO(bill): Actually handle correctly
-	isize      type_level; // TODO(bill): Actually handle correctly
 	String     proc_name;
 	Type *     type_hint;
 	DeclInfo * curr_proc_decl;
 	Type *     curr_proc_sig;
 	ForeignContext foreign_context;
 
+	CheckerTypePath *type_path;
+	isize            type_level; // TODO(bill): Actually handle correctly
+
 	bool       collect_delayed_decls;
 	bool       allow_polymorphic_types;
 	bool       no_polymorphic_errors;
@@ -382,7 +386,6 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes);
 void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
 void check_delayed_file_import_entity(Checker *c, AstNode *decl);
 
-
 struct AttributeContext {
 	String  link_name;
 	String  link_prefix;
@@ -401,3 +404,9 @@ AttributeContext make_attribute_context(String link_prefix) {
 typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
 
 void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
+
+CheckerTypePath *new_checker_type_path();
+void destroy_checker_type_path(CheckerTypePath *tp);
+
+void    check_type_path_push(Checker *c, Entity *e);
+Entity *check_type_path_pop (Checker *c);

+ 38 - 38
src/entity.cpp

@@ -177,7 +177,8 @@ bool is_entity_exported(Entity *e) {
 
 gb_global u64 global_entity_id = 0;
 
-Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
+Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
+	gbAllocator a = heap_allocator();
 	Entity *entity = gb_alloc_item(a, Entity);
 	entity->kind   = kind;
 	entity->state  = EntityState_Unresolved;
@@ -188,17 +189,17 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
 	return entity;
 }
 
-Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_immutable, EntityState state = EntityState_Unresolved) {
-	Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
+Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_immutable, EntityState state = EntityState_Unresolved) {
+	Entity *entity = alloc_entity(Entity_Variable, scope, token, type);
 	entity->Variable.is_immutable = is_immutable;
 	entity->state = state;
 	return entity;
 }
 
-Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
+Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
 	GB_ASSERT(parent != nullptr);
 	token.pos = parent->token.pos;
-	Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
+	Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
 	entity->using_parent = parent;
 	entity->parent_proc_decl = parent->parent_proc_decl;
 	entity->flags |= EntityFlag_Using;
@@ -208,21 +209,21 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
 }
 
 
-Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
-	Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
+Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
+	Entity *entity = alloc_entity(Entity_Constant, scope, token, type);
 	entity->Constant.value = value;
 	return entity;
 }
 
-Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
-	Entity *entity = alloc_entity(a, Entity_TypeName, scope, token, type);
+Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
+	Entity *entity = alloc_entity(Entity_TypeName, scope, token, type);
 	entity->state = state;
 	return entity;
 }
 
-Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
+Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
 	bool is_immutable = false;
-	Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
+	Entity *entity = alloc_entity_variable(scope, token, type, is_immutable);
 	entity->flags |= EntityFlag_Used;
 	entity->flags |= EntityFlag_Param;
 	entity->state = EntityState_Resolved;
@@ -232,8 +233,8 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
 }
 
 
-Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
-	Entity *entity = make_entity_constant(a, scope, token, type, value);
+Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
+	Entity *entity = alloc_entity_constant(scope, token, type, value);
 	entity->flags |= EntityFlag_Used;
 	if (poly_const) entity->flags |= EntityFlag_PolyConst;
 	entity->flags |= EntityFlag_Param;
@@ -241,8 +242,8 @@ Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *
 }
 
 
-Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index, EntityState state = EntityState_Unresolved) {
-	Entity *entity = make_entity_variable(a, scope, token, type, false);
+Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index, EntityState state = EntityState_Unresolved) {
+	Entity *entity = alloc_entity_variable(scope, token, type, false);
 	entity->Variable.field_src_index = field_src_index;
 	entity->Variable.field_index = field_src_index;
 	if (is_using) entity->flags |= EntityFlag_Using;
@@ -251,8 +252,8 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
 	return entity;
 }
 
-Entity *make_entity_array_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
-	Entity *entity = make_entity_variable(a, scope, token, type, false);
+Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_src_index) {
+	Entity *entity = alloc_entity_variable(scope, token, type, false);
 	entity->Variable.field_src_index = field_src_index;
 	entity->Variable.field_index = field_src_index;
 	entity->flags |= EntityFlag_Field;
@@ -261,34 +262,34 @@ Entity *make_entity_array_elem(gbAllocator a, Scope *scope, Token token, Type *t
 	return entity;
 }
 
-Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type, u64 tags) {
-	Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
+Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
+	Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
 	entity->Procedure.tags = tags;
 	return entity;
 }
 
-Entity *make_entity_proc_group(gbAllocator a, Scope *scope, Token token, Type *type) {
-	Entity *entity = alloc_entity(a, Entity_ProcGroup, scope, token, type);
+Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
+	Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type);
 	return entity;
 }
 
 
-Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
-	Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
+Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) {
+	Entity *entity = alloc_entity(Entity_Builtin, scope, token, type);
 	entity->Builtin.id = id;
 	entity->state = EntityState_Resolved;
 	return entity;
 }
 
-Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
-	Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
+Entity *alloc_entity_alias(Scope *scope, Token token, Type *type, Entity *base) {
+	Entity *entity = alloc_entity(Entity_Alias, scope, token, type);
 	entity->Alias.base = base;
 	return entity;
 }
 
-Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
-                                String path, String name, Scope *import_scope) {
-	Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
+Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
+                                 String path, String name, Scope *import_scope) {
+	Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
 	entity->ImportName.path = path;
 	entity->ImportName.name = name;
 	entity->ImportName.scope = import_scope;
@@ -296,9 +297,9 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
 	return entity;
 }
 
-Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
-                                 String path, String name) {
-	Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
+Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
+                                  String path, String name) {
+	Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
 	entity->LibraryName.path = path;
 	entity->LibraryName.name = name;
 	entity->state = EntityState_Resolved; // TODO(bill): Is this correct?
@@ -309,21 +310,20 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
 
 
 
-Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
-	Entity *entity = alloc_entity(a, Entity_Nil, nullptr, make_token_ident(name), type);
+Entity *alloc_entity_nil(String name, Type *type) {
+	Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type);
 	return entity;
 }
 
-Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
-                          AstNode *node) {
-	Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
+Entity *alloc_entity_label(Scope *scope, Token token, Type *type, AstNode *node) {
+	Entity *entity = alloc_entity(Entity_Label, scope, token, type);
 	entity->Label.node = node;
 	entity->state = EntityState_Resolved;
 	return entity;
 }
 
-Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
+Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
 	token.string = str_lit("_");
-	return make_entity_variable(a, scope, token, nullptr, false);
+	return alloc_entity_variable(scope, token, nullptr, false);
 }
 

+ 32 - 42
src/ir.cpp

@@ -1206,10 +1206,7 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi
 
 	String s = make_string_c(text);
 
-	Entity *e = make_entity_variable(a, nullptr,
-	                                 make_token_ident(s),
-	                                 alloc_type_array(elem_type, count),
-	                                 false);
+	Entity *e = alloc_entity_variable(nullptr, make_token_ident(s), alloc_type_array(elem_type, count), false);
 	irValue *value = ir_value_global(a, e, nullptr);
 	value->Global.is_private = true;
 	ir_module_add_value(m, e, value);
@@ -1308,7 +1305,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
 
 		String name = make_string(str, len-1);
 
-		Entity *e = make_entity_constant(a, nullptr, make_token_ident(name), t, value);
+		Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
 		irValue *g = ir_value_global(a, e, backing_array);
 		ir_module_add_value(m, e, g);
 		map_set(&m->members, hash_string(name), g);
@@ -1335,7 +1332,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
 	token.string = name;
 	Type *type = alloc_type_array(t_u8, string.len+1);
 	ExactValue ev = exact_value_string(string);
-	Entity *entity = make_entity_constant(a, nullptr, token, type, ev);
+	Entity *entity = alloc_entity_constant(nullptr, token, type, ev);
 	irValue *g = ir_value_global(a, entity, ir_add_module_constant(m, type, ev));
 	g->Global.is_private      = true;
 	g->Global.is_unnamed_addr = true;
@@ -1429,10 +1426,7 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type, bool zero_initial
 	if (proc->curr_block) {
 		scope = proc->curr_block->scope;
 	}
-	Entity *e = make_entity_variable(proc->module->allocator,
-	                                 scope,
-	                                 empty_token,
-	                                 type, false);
+	Entity *e = alloc_entity_variable(scope, empty_token, type, false);
 	return ir_add_local(proc, e, nullptr, zero_initialized);
 }
 
@@ -1450,11 +1444,7 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) {
 	String name = make_string(str, len-1);
 
 	Scope *scope = nullptr;
-	Entity *e = make_entity_variable(a,
-	                                 scope,
-	                                 make_token_ident(name),
-	                                 type, false);
-
+	Entity *e = alloc_entity_variable(scope, make_token_ident(name), type, false);
 	irValue *g = ir_value_global(a, e, value);
 	ir_module_add_value(m, e, g);
 	map_set(&m->members, hash_string(name), g);
@@ -7389,7 +7379,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
 	if (proc->type->Proc.return_by_pointer) {
 		// NOTE(bill): this must be the first parameter stored
 		Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results));
-		Entity *e = make_entity_param(a, nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
+		Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
 		e->flags |= EntityFlag_Sret | EntityFlag_NoAlias;
 
 		irValue *param = ir_value_param(a, proc, e, ptr_type);
@@ -7472,7 +7462,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
 
 
 	if (proc->type->Proc.calling_convention == ProcCC_Odin) {
-		Entity *e = make_entity_param(a, nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
+		Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
 		e->flags |= EntityFlag_NoAlias;
 		irValue *param = ir_value_param(a, proc, e, e->type);
 		ir_module_add_value(proc->module, e, param);
@@ -7633,7 +7623,7 @@ void ir_init_module(irModule *m, Checker *c) {
 			isize max_type_info_count = m->info->type_info_types.count;
 
 			String name = str_lit(IR_TYPE_INFO_DATA_NAME);
-			Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name), alloc_type_array(t_type_info, max_type_info_count), false);
+			Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), alloc_type_array(t_type_info, max_type_info_count), false);
 			irValue *g = ir_value_global(m->allocator, e, nullptr);
 			g->Global.is_private = true;
 			ir_module_add_value(m, e, g);
@@ -7664,8 +7654,8 @@ void ir_init_module(irModule *m, Checker *c) {
 
 			{
 				String name = str_lit(IR_TYPE_INFO_TYPES_NAME);
-				Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
-				                                 alloc_type_array(t_type_info_ptr, count), false);
+				Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+				                                  alloc_type_array(t_type_info_ptr, count), false);
 				irValue *g = ir_value_global(m->allocator, e, nullptr);
 				ir_module_add_value(m, e, g);
 				map_set(&m->members, hash_string(name), g);
@@ -7673,8 +7663,8 @@ void ir_init_module(irModule *m, Checker *c) {
 			}
 			{
 				String name = str_lit(IR_TYPE_INFO_NAMES_NAME);
-				Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
-				                                 alloc_type_array(t_string, count), false);
+				Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+				                                  alloc_type_array(t_string, count), false);
 				irValue *g = ir_value_global(m->allocator, e, nullptr);
 				ir_module_add_value(m, e, g);
 				map_set(&m->members, hash_string(name), g);
@@ -7682,8 +7672,8 @@ void ir_init_module(irModule *m, Checker *c) {
 			}
 			{
 				String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME);
-				Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
-				                                 alloc_type_array(t_uintptr, count), false);
+				Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+				                                  alloc_type_array(t_uintptr, count), false);
 				irValue *g = ir_value_global(m->allocator, e, nullptr);
 				ir_module_add_value(m, e, g);
 				map_set(&m->members, hash_string(name), g);
@@ -7692,8 +7682,8 @@ void ir_init_module(irModule *m, Checker *c) {
 
 			{
 				String name = str_lit(IR_TYPE_INFO_USINGS_NAME);
-				Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
-				                                 alloc_type_array(t_bool, count), false);
+				Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
+				                                  alloc_type_array(t_bool, count), false);
 				irValue *g = ir_value_global(m->allocator, e, nullptr);
 				ir_module_add_value(m, e, g);
 				map_set(&m->members, hash_string(name), g);
@@ -8487,12 +8477,12 @@ void ir_gen_tree(irGen *s) {
 		array_init(&proc_params->Tuple.variables, a, 3);
 		array_init(&proc_results->Tuple.variables, a, 1);
 
-		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
-		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
-		proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
+		proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false, false);
+		proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
+		proc_params->Tuple.variables[2] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false, false);
 
 
-		proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
+		proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false, false);
 
 
 		Type *proc_type = alloc_type_proc(proc_scope,
@@ -8507,7 +8497,7 @@ void ir_gen_tree(irGen *s) {
 		proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
 
 		AstNode *body = gb_alloc_item(a, AstNode);
-		Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
+		Entity *e = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
 		irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
 
 		map_set(&m->values, hash_entity(e), p);
@@ -8566,11 +8556,11 @@ void ir_gen_tree(irGen *s) {
 		array_init(&proc_results->Tuple.variables, a, 1);
 
 		Type *cstring_ptr = alloc_type_pointer(t_cstring);
-		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
-		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argv")), cstring_ptr, false, false);
+		proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
+		proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, make_token_ident(str_lit("argv")), cstring_ptr, false, false);
 
 
-		proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
+		proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false, false);
 
 
 		Type *proc_type = alloc_type_proc(proc_scope,
@@ -8585,7 +8575,7 @@ void ir_gen_tree(irGen *s) {
 		proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
 
 		AstNode *body = gb_alloc_item(a, AstNode);
-		Entity *e     = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
+		Entity *e     = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
 		irValue *p    = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
 
 		map_set(&m->values, hash_entity(e), p);
@@ -8636,12 +8626,12 @@ void ir_gen_tree(irGen *s) {
 		proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
 		proc_results->Tuple.variable_count = 1;
 
-		proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
-		proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
-		proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false);
-		proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32,    false);
+		proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false);
+		proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false);
+		proc_params->Tuple.variables[2] = alloc_entity_param(proc_scope, blank_token, t_u8_ptr, false);
+		proc_params->Tuple.variables[3] = alloc_entity_param(proc_scope, blank_token, t_i32,    false);
 
-		proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
+		proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false);
 
 
 		Type *proc_type = alloc_type_proc(a, proc_scope,
@@ -8649,7 +8639,7 @@ void ir_gen_tree(irGen *s) {
 		                                 proc_results, 1, false, ProcCC_Std);
 
 		AstNode *body = gb_alloc_item(a, AstNode);
-		Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
+		Entity *e = alloc_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
 		irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
 
 		m->entry_point_entity = e;
@@ -8675,7 +8665,7 @@ void ir_gen_tree(irGen *s) {
 		                                  nullptr, 0, false,
 		                                  ProcCC_Contextless);
 		AstNode *body = gb_alloc_item(a, AstNode);
-		Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
+		Entity *e = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
 		irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
 
 		map_set(&m->values, hash_entity(e), p);

+ 2 - 0
src/main.cpp

@@ -685,6 +685,8 @@ i32 exec_llvm_llc(String output_base) {
 #endif
 }
 
+
+
 int main(int arg_count, char **arg_ptr) {
 	if (arg_count < 2) {
 		usage(make_string_c(arg_ptr[0]));

+ 14 - 5
src/types.cpp

@@ -435,8 +435,12 @@ HashKey hash_cache_type_array(Type *elem, i64 count) {
 	return hash_ptr_and_id(elem, cast(u64)count);
 }
 HashKey hash_cache_type_map(Type *key, Type *value) {
-	u64 v = cast(u64)cast(uintptr)value;
-	return hash_ptr_and_id(key, v);
+	HashKey hkey = {};
+	if ((key != nullptr) == (value != nullptr)) {
+		u64 v = cast(u64)cast(uintptr)value;
+		hkey = hash_ptr_and_id(key, v);
+	}
+	return hkey;
 }
 
 
@@ -453,6 +457,7 @@ void init_cached_type_maps() {
 CachedType *find_cached_type(CachedTypeKind kind, HashKey key) {
 	GB_ASSERT(key.kind == HashKey_PtrAndId);
 	if (key.ptr_and_id.ptr == nullptr) {
+		// NOTE(bill): uncachable types
 		return nullptr;
 	}
 	auto *m = &cached_type_maps[kind];
@@ -462,6 +467,7 @@ CachedType *find_cached_type(CachedTypeKind kind, HashKey key) {
 void add_cached_type(CachedTypeKind kind, HashKey key, Type *type) {
 	GB_ASSERT(key.kind == HashKey_PtrAndId);
 	if (key.ptr_and_id.ptr == nullptr) {
+		// NOTE(bill): uncachable types
 		return;
 	}
 	CachedType ct = {};
@@ -1694,10 +1700,10 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 			String data_str = str_lit("data");
 			String type_info_str = str_lit("type_info");
 			if (entity__any_data == nullptr) {
-				entity__any_data = make_entity_field(a, nullptr, make_token_ident(data_str), t_rawptr, false, 0);
+				entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0);
 			}
 			if (entity__any_type_info == nullptr) {
-				entity__any_type_info = make_entity_field(a, nullptr, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
+				entity__any_type_info = alloc_entity_field(nullptr, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
 			}
 
 			if (field_name == data_str) {
@@ -1722,7 +1728,7 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 			case (_length): \
 				if (field_name == _name) { \
 					selection_add_index(&sel, (_length)-1); \
-					sel.entity = make_entity_array_elem(a, nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
+					sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
 					return sel; \
 				} \
 				/*fallthrough*/
@@ -1853,11 +1859,14 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 }
 
 
+// IMPORTANT TODO(bill): SHould this TypePath code be removed since type cycle checking is handled much earlier on?
+
 struct TypePath {
 	Array<Entity *> path; // Entity_TypeName;
 	bool failure;
 };
 
+
 void type_path_init(TypePath *tp) {
 	// TODO(bill): Use an allocator that uses a backing array if it can and then use alternative allocator when exhausted
 	array_init(&tp->path, heap_allocator());