Browse Source

Remove `using` in arrays; Remove `_` non-exported struct fields
Start determining slow parts of the compiler

gingerBill 7 years ago
parent
commit
cfabc0e61f
9 changed files with 299 additions and 369 deletions
  1. 0 84
      src/check_expr.cpp
  2. 202 198
      src/check_stmt.cpp
  3. 8 54
      src/check_type.cpp
  4. 34 3
      src/checker.cpp
  5. 2 13
      src/ir.cpp
  6. 0 2
      src/ir_print.cpp
  7. 2 3
      src/main.cpp
  8. 39 11
      src/timings.cpp
  9. 12 1
      src/types.cpp

+ 0 - 84
src/check_expr.cpp

@@ -2541,27 +2541,6 @@ isize entity_overload_count(Scope *s, String name) {
 	return 1;
 	return 1;
 }
 }
 
 
-bool check_is_field_exported(Checker *c, Entity *field) {
-	if (field == nullptr) {
-		// NOTE(bill): Just incase
-		return true;
-	}
-	if (field->kind != Entity_Variable) {
-		return true;
-	}
-	Scope *file_scope = field->scope;
-	if (file_scope == nullptr) {
-		return true;
-	}
-	while (file_scope->file == nullptr) {
-		file_scope = file_scope->parent;
-	}
-	if (!is_entity_exported(field) && file_scope != c->context.file_scope) {
-		return false;
-	}
-	return true;
-}
-
 Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
 Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
 	ast_node(se, SelectorExpr, node);
 	ast_node(se, SelectorExpr, node);
 
 
@@ -2730,13 +2709,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
 	if (entity == nullptr && selector->kind == AstNode_Ident) {
 	if (entity == nullptr && selector->kind == AstNode_Ident) {
 		String field_name = selector->Ident.token.string;
 		String field_name = selector->Ident.token.string;
 		sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type);
 		sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type);
-
-		if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) {
-			error(op_expr, "'%.*s' is an unexported field", LIT(field_name));
-			operand->mode = Addressing_Invalid;
-			operand->expr = node;
-			return nullptr;
-		}
 		entity = sel.entity;
 		entity = sel.entity;
 
 
 		// NOTE(bill): Add type info needed for fields like 'names'
 		// NOTE(bill): Add type info needed for fields like 'names'
@@ -4718,29 +4690,6 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
 }
 }
 
 
 
 
-Entity *find_using_index_expr(Type *t) {
-	t = base_type(t);
-	if (t->kind != Type_Struct) {
-		return nullptr;
-	}
-
-	for_array(i, t->Struct.fields) {
-		Entity *f = t->Struct.fields[i];
-		if (f->kind == Entity_Variable &&
-		    (f->flags & EntityFlag_Field) != 0 &&
-		    (f->flags & EntityFlag_Using) != 0) {
-			if (is_type_indexable(f->type)) {
-				return f;
-			}
-			Entity *res = find_using_index_expr(f->type);
-			if (res != nullptr) {
-				return res;
-			}
-		}
-	}
-	return nullptr;
-}
-
 isize lookup_polymorphic_struct_parameter(TypeStruct *st, String parameter_name) {
 isize lookup_polymorphic_struct_parameter(TypeStruct *st, String parameter_name) {
 	if (!st->is_polymorphic) return -1;
 	if (!st->is_polymorphic) return -1;
 
 
@@ -5531,11 +5480,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 							error(elem, "Unknown field '%.*s' in structure literal", LIT(name));
 							error(elem, "Unknown field '%.*s' in structure literal", LIT(name));
 							continue;
 							continue;
 						}
 						}
-						if (!is_unknown && !check_is_field_exported(c, sel.entity)) {
-							error(elem, "Cannot assign to an unexported field '%.*s' in structure literal", LIT(name));
-							continue;
-						}
-
 
 
 						if (sel.index.count > 1) {
 						if (sel.index.count > 1) {
 							error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name));
 							error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name));
@@ -5564,15 +5508,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 						check_assignment(c, o, field->type, str_lit("structure literal"));
 						check_assignment(c, o, field->type, str_lit("structure literal"));
 					}
 					}
 				} else {
 				} else {
-					bool all_fields_are_blank = true;
-					for_array(i, t->Struct.fields_in_src_order) {
-						Entity *field = t->Struct.fields_in_src_order[i];
-						if (!is_blank_ident(field->token)) {
-							all_fields_are_blank = false;
-							break;
-						}
-					}
-
 					bool seen_field_value = false;
 					bool seen_field_value = false;
 
 
 					for_array(index, cl->elems) {
 					for_array(index, cl->elems) {
@@ -5594,21 +5529,9 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 						if (field == nullptr) {
 						if (field == nullptr) {
 							field = t->Struct.fields_in_src_order[index];
 							field = t->Struct.fields_in_src_order[index];
 						}
 						}
-						if (!all_fields_are_blank && is_blank_ident(field->token)) {
-							// NOTE(bill): Ignore blank identifiers
-							continue;
-						}
 
 
 						check_expr_with_type_hint(c, o, elem, field->type);
 						check_expr_with_type_hint(c, o, elem, field->type);
 
 
-						if (!check_is_field_exported(c, field)) {
-							gbString t = type_to_string(type);
-							error(o->expr, "Implicit assignment to an unexported field '%.*s' in '%s' literal",
-							           LIT(field->token.string), t);
-							gb_string_free(t);
-							continue;
-						}
-
 						if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) {
 						if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) {
 							is_constant = false;
 							is_constant = false;
 						}
 						}
@@ -6032,13 +5955,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 			valid = false;
 			valid = false;
 		}
 		}
 
 
-		if (!valid && t->kind == Type_Struct) {
-			Entity *found = find_using_index_expr(t);
-			if (found != nullptr) {
-				valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count);
-			}
-		}
-
 		if (!valid) {
 		if (!valid) {
 			gbString str = expr_to_string(o->expr);
 			gbString str = expr_to_string(o->expr);
 			gbString type_str = type_to_string(o->type);
 			gbString type_str = type_to_string(o->type);

+ 202 - 198
src/check_stmt.cpp

@@ -41,7 +41,6 @@ void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
 
 
 		check_stmt(c, n, new_flags);
 		check_stmt(c, n, new_flags);
 	}
 	}
-
 }
 }
 
 
 bool check_is_terminating_list(Array<AstNode *> stmts) {
 bool check_is_terminating_list(Array<AstNode *> stmts) {
@@ -576,6 +575,207 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
 	return true;
 	return true;
 }
 }
 
 
+void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
+	ast_node(ss, SwitchStmt, node);
+
+	Operand x = {};
+
+	mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed;
+	check_open_scope(c, node);
+	defer (check_close_scope(c));
+
+	check_label(c, ss->label); // TODO(bill): What should the label's "scope" be?
+
+	if (ss->init != nullptr) {
+		check_stmt(c, ss->init, 0);
+	}
+	if (ss->tag != nullptr) {
+		check_expr(c, &x, ss->tag);
+		check_assignment(c, &x, nullptr, str_lit("switch expression"));
+	} else {
+		x.mode  = Addressing_Constant;
+		x.type  = t_bool;
+		x.value = exact_value_bool(true);
+
+		Token token  = {};
+		token.pos    = ast_node_token(ss->body).pos;
+		token.string = str_lit("true");
+		x.expr       = ast_ident(c->curr_ast_file, token);
+	}
+	if (is_type_vector(x.type)) {
+		gbString str = type_to_string(x.type);
+		error(x.expr, "Invalid switch expression type: %s", str);
+		gb_string_free(str);
+		return;
+	}
+
+
+	// NOTE(bill): Check for multiple defaults
+	AstNode *first_default = nullptr;
+	ast_node(bs, BlockStmt, ss->body);
+	for_array(i, bs->stmts) {
+		AstNode *stmt = bs->stmts[i];
+		AstNode *default_stmt = nullptr;
+		if (stmt->kind == AstNode_CaseClause) {
+			ast_node(cc, CaseClause, stmt);
+			if (cc->list.count == 0) {
+				default_stmt = stmt;
+			}
+		} else {
+			error(stmt, "Invalid AST - expected case clause");
+		}
+
+		if (default_stmt != nullptr) {
+			if (first_default != nullptr) {
+				TokenPos pos = ast_node_token(first_default).pos;
+				error(stmt,
+				           "multiple default clauses\n"
+				           "\tfirst at %.*s(%td:%td)",
+				           LIT(pos.file), pos.line, pos.column);
+			} else {
+				first_default = default_stmt;
+			}
+		}
+	}
+
+	Map<TypeAndToken> seen = {}; // NOTE(bill): Multimap
+	map_init(&seen, heap_allocator());
+	defer (map_destroy(&seen));
+
+	for_array(stmt_index, bs->stmts) {
+		AstNode *stmt = bs->stmts[stmt_index];
+		if (stmt->kind != AstNode_CaseClause) {
+			// NOTE(bill): error handled by above multiple default checker
+			continue;
+		}
+		ast_node(cc, CaseClause, stmt);
+
+		for_array(j, cc->list) {
+			AstNode *expr = unparen_expr(cc->list[j]);
+
+			if (is_ast_node_a_range(expr)) {
+				ast_node(ie, BinaryExpr, expr);
+				Operand lhs = {};
+				Operand rhs = {};
+				check_expr(c, &lhs, ie->left);
+				if (x.mode == Addressing_Invalid) {
+					continue;
+				}
+				if (lhs.mode == Addressing_Invalid) {
+					continue;
+				}
+				check_expr(c, &rhs, ie->right);
+				if (rhs.mode == Addressing_Invalid) {
+					continue;
+				}
+
+				if (!is_type_ordered(x.type)) {
+					gbString str = type_to_string(x.type);
+					error(expr, "Unordered type '%s', is invalid for an interval expression", str);
+					gb_string_free(str);
+					continue;
+				}
+
+
+				TokenKind op = Token_Invalid;
+
+				Operand a = lhs;
+				Operand b = rhs;
+				check_comparison(c, &a, &x, Token_LtEq);
+				if (a.mode == Addressing_Invalid) {
+					continue;
+				}
+				switch (ie->op.kind) {
+				case Token_Ellipsis:   op = Token_GtEq; break;
+				case Token_HalfClosed: op = Token_Gt;   break;
+				default: error(ie->op, "Invalid interval operator"); continue;
+				}
+
+				check_comparison(c, &b, &x, op);
+				if (b.mode == Addressing_Invalid) {
+					continue;
+				}
+
+				switch (ie->op.kind) {
+				case Token_Ellipsis:   op = Token_LtEq; break;
+				case Token_HalfClosed: op = Token_Lt;   break;
+				default: error(ie->op, "Invalid interval operator"); continue;
+				}
+
+				Operand a1 = lhs;
+				Operand b1 = rhs;
+				check_comparison(c, &a1, &b1, op);
+			} else {
+				Operand y = {};
+				check_expr(c, &y, expr);
+
+				if (x.mode == Addressing_Invalid ||
+				    y.mode == Addressing_Invalid) {
+					continue;
+				}
+
+				convert_to_typed(c, &y, x.type);
+				if (y.mode == Addressing_Invalid) {
+					continue;
+				}
+
+				// NOTE(bill): the ordering here matters
+				Operand z = y;
+				check_comparison(c, &z, &x, Token_CmpEq);
+				if (z.mode == Addressing_Invalid) {
+					continue;
+				}
+				if (y.mode != Addressing_Constant) {
+					continue;
+				}
+
+
+				if (y.value.kind != ExactValue_Invalid) {
+					HashKey key = hash_exact_value(y.value);
+					TypeAndToken *found = map_get(&seen, key);
+					if (found != nullptr) {
+						gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+						defer (gb_temp_arena_memory_end(tmp));
+
+						isize count = multi_map_count(&seen, key);
+						TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
+
+						multi_map_get_all(&seen, key, taps);
+						bool continue_outer = false;
+
+						for (isize i = 0; i < count; i++) {
+							TypeAndToken tap = taps[i];
+							if (are_types_identical(y.type, tap.type)) {
+								TokenPos pos = tap.token.pos;
+								gbString expr_str = expr_to_string(y.expr);
+								error(y.expr,
+								           "Duplicate case '%s'\n"
+								           "\tprevious case at %.*s(%td:%td)",
+								           expr_str,
+								           LIT(pos.file), pos.line, pos.column);
+								gb_string_free(expr_str);
+								continue_outer = true;
+								break;
+							}
+						}
+
+
+						if (continue_outer) {
+							continue;
+						}
+					}
+					TypeAndToken tap = {y.type, ast_node_token(y.expr)};
+					multi_map_insert(&seen, key, tap);
+				}
+			}
+		}
+
+		check_open_scope(c, stmt);
+		check_stmt_list(c, cc->stmts, mod_flags);
+		check_close_scope(c);
+	}
+}
+
 void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 	u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
 	u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
 	switch (node->kind) {
 	switch (node->kind) {
@@ -940,7 +1140,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 				check_assignment(c, &operands[i], e->type, str_lit("return statement"));
 				check_assignment(c, &operands[i], e->type, str_lit("return statement"));
 			}
 			}
 		}
 		}
-
 	case_end;
 	case_end;
 
 
 	case_ast_node(fs, ForStmt, node);
 	case_ast_node(fs, ForStmt, node);
@@ -1193,202 +1392,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 	case_end;
 	case_end;
 
 
 	case_ast_node(ss, SwitchStmt, node);
 	case_ast_node(ss, SwitchStmt, node);
-		Operand x = {};
-
-		mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed;
-		check_open_scope(c, node);
-		defer (check_close_scope(c));
-
-		check_label(c, ss->label); // TODO(bill): What should the label's "scope" be?
-
-		if (ss->init != nullptr) {
-			check_stmt(c, ss->init, 0);
-		}
-		if (ss->tag != nullptr) {
-			check_expr(c, &x, ss->tag);
-			check_assignment(c, &x, nullptr, str_lit("switch expression"));
-		} else {
-			x.mode  = Addressing_Constant;
-			x.type  = t_bool;
-			x.value = exact_value_bool(true);
-
-			Token token  = {};
-			token.pos    = ast_node_token(ss->body).pos;
-			token.string = str_lit("true");
-			x.expr       = ast_ident(c->curr_ast_file, token);
-		}
-		if (is_type_vector(x.type)) {
-			gbString str = type_to_string(x.type);
-			error(x.expr, "Invalid switch expression type: %s", str);
-			gb_string_free(str);
-			break;
-		}
-
-
-		// NOTE(bill): Check for multiple defaults
-		AstNode *first_default = nullptr;
-		ast_node(bs, BlockStmt, ss->body);
-		for_array(i, bs->stmts) {
-			AstNode *stmt = bs->stmts[i];
-			AstNode *default_stmt = nullptr;
-			if (stmt->kind == AstNode_CaseClause) {
-				ast_node(cc, CaseClause, stmt);
-				if (cc->list.count == 0) {
-					default_stmt = stmt;
-				}
-			} else {
-				error(stmt, "Invalid AST - expected case clause");
-			}
-
-			if (default_stmt != nullptr) {
-				if (first_default != nullptr) {
-					TokenPos pos = ast_node_token(first_default).pos;
-					error(stmt,
-					           "multiple default clauses\n"
-					           "\tfirst at %.*s(%td:%td)",
-					           LIT(pos.file), pos.line, pos.column);
-				} else {
-					first_default = default_stmt;
-				}
-			}
-		}
-
-		Map<TypeAndToken> seen = {}; // NOTE(bill): Multimap
-		map_init(&seen, heap_allocator());
-		defer (map_destroy(&seen));
-
-		for_array(stmt_index, bs->stmts) {
-			AstNode *stmt = bs->stmts[stmt_index];
-			if (stmt->kind != AstNode_CaseClause) {
-				// NOTE(bill): error handled by above multiple default checker
-				continue;
-			}
-			ast_node(cc, CaseClause, stmt);
-
-			for_array(j, cc->list) {
-				AstNode *expr = unparen_expr(cc->list[j]);
-
-				if (is_ast_node_a_range(expr)) {
-					ast_node(ie, BinaryExpr, expr);
-					Operand lhs = {};
-					Operand rhs = {};
-					check_expr(c, &lhs, ie->left);
-					if (x.mode == Addressing_Invalid) {
-						continue;
-					}
-					if (lhs.mode == Addressing_Invalid) {
-						continue;
-					}
-					check_expr(c, &rhs, ie->right);
-					if (rhs.mode == Addressing_Invalid) {
-						continue;
-					}
-
-					if (!is_type_ordered(x.type)) {
-						gbString str = type_to_string(x.type);
-						error(expr, "Unordered type '%s', is invalid for an interval expression", str);
-						gb_string_free(str);
-						continue;
-					}
-
-
-					TokenKind op = Token_Invalid;
-
-					Operand a = lhs;
-					Operand b = rhs;
-					check_comparison(c, &a, &x, Token_LtEq);
-					if (a.mode == Addressing_Invalid) {
-						continue;
-					}
-					switch (ie->op.kind) {
-					case Token_Ellipsis:   op = Token_GtEq; break;
-					case Token_HalfClosed: op = Token_Gt;   break;
-					default: error(ie->op, "Invalid interval operator"); continue;
-					}
-
-					check_comparison(c, &b, &x, op);
-					if (b.mode == Addressing_Invalid) {
-						continue;
-					}
-
-					switch (ie->op.kind) {
-					case Token_Ellipsis:   op = Token_LtEq; break;
-					case Token_HalfClosed: op = Token_Lt;   break;
-					default: error(ie->op, "Invalid interval operator"); continue;
-					}
-
-					Operand a1 = lhs;
-					Operand b1 = rhs;
-					check_comparison(c, &a1, &b1, op);
-				} else {
-					Operand y = {};
-					check_expr(c, &y, expr);
-
-					if (x.mode == Addressing_Invalid ||
-					    y.mode == Addressing_Invalid) {
-						continue;
-					}
-
-					convert_to_typed(c, &y, x.type);
-					if (y.mode == Addressing_Invalid) {
-						continue;
-					}
-
-					// NOTE(bill): the ordering here matters
-					Operand z = y;
-					check_comparison(c, &z, &x, Token_CmpEq);
-					if (z.mode == Addressing_Invalid) {
-						continue;
-					}
-					if (y.mode != Addressing_Constant) {
-						continue;
-					}
-
-
-					if (y.value.kind != ExactValue_Invalid) {
-						HashKey key = hash_exact_value(y.value);
-						TypeAndToken *found = map_get(&seen, key);
-						if (found != nullptr) {
-							gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
-							defer (gb_temp_arena_memory_end(tmp));
-
-							isize count = multi_map_count(&seen, key);
-							TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
-
-							multi_map_get_all(&seen, key, taps);
-							bool continue_outer = false;
-
-							for (isize i = 0; i < count; i++) {
-								TypeAndToken tap = taps[i];
-								if (are_types_identical(y.type, tap.type)) {
-									TokenPos pos = tap.token.pos;
-									gbString expr_str = expr_to_string(y.expr);
-									error(y.expr,
-									           "Duplicate case '%s'\n"
-									           "\tprevious case at %.*s(%td:%td)",
-									           expr_str,
-									           LIT(pos.file), pos.line, pos.column);
-									gb_string_free(expr_str);
-									continue_outer = true;
-									break;
-								}
-							}
-
-
-							if (continue_outer) {
-								continue;
-							}
-						}
-						TypeAndToken tap = {y.type, ast_node_token(y.expr)};
-						multi_map_insert(&seen, key, tap);
-					}
-				}
-			}
-
-			check_open_scope(c, stmt);
-			check_stmt_list(c, cc->stmts, mod_flags);
-			check_close_scope(c);
-		}
+		check_switch_stmt(c, node, mod_flags);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ss, TypeSwitchStmt, node);
 	case_ast_node(ss, TypeSwitchStmt, node);

+ 8 - 54
src/check_type.cpp

@@ -208,7 +208,6 @@ void check_struct_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields,
 
 
 	}
 	}
 
 
-	Entity *using_index_expr = nullptr;
 
 
 	if (is_using && fields->count > 0) {
 	if (is_using && fields->count > 0) {
 		Type *first_type = (*fields)[fields->count-1]->type;
 		Type *first_type = (*fields)[fields->count-1]->type;
@@ -217,32 +216,10 @@ void check_struct_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields,
 		    vd->names.count >= 1 &&
 		    vd->names.count >= 1 &&
 		    vd->names[0]->kind == AstNode_Ident) {
 		    vd->names[0]->kind == AstNode_Ident) {
 			Token name_token = vd->names[0]->Ident.token;
 			Token name_token = vd->names[0]->Ident.token;
-			if (is_type_indexable(t)) {
-				bool ok = true;
-				for_array(emi, entity_map->entries) {
-					Entity *e = entity_map->entries[emi].value;
-					if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
-						if (is_type_indexable(e->type)) {
-							if (e->identifier != vd->names[0]) {
-								ok = false;
-								using_index_expr = e;
-								break;
-							}
-						}
-					}
-				}
-				if (ok) {
-					using_index_expr = (*fields)[fields->count-1];
-				} else {
-					(*fields)[fields->count-1]->flags &= ~EntityFlag_Using;
-					error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string));
-				}
-			} else {
-				gbString type_str = type_to_string(first_type);
-				error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
-				gb_string_free(type_str);
-				return;
-			}
+			gbString type_str = type_to_string(first_type);
+			error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
+			gb_string_free(type_str);
+			return;
 		}
 		}
 
 
 		populate_using_entity_map(c, struct_node, type, entity_map);
 		populate_using_entity_map(c, struct_node, type, entity_map);
@@ -408,7 +385,6 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
 			field_src_index += 1;
 			field_src_index += 1;
 		}
 		}
 
 
-		Entity *using_index_expr = nullptr;
 
 
 		if (is_using && p->names.count > 0) {
 		if (is_using && p->names.count > 0) {
 			Type *first_type = fields[fields.count-1]->type;
 			Type *first_type = fields[fields.count-1]->type;
@@ -418,32 +394,10 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
 			    p->names.count >= 1 &&
 			    p->names.count >= 1 &&
 			    p->names[0]->kind == AstNode_Ident) {
 			    p->names[0]->kind == AstNode_Ident) {
 				Token name_token = p->names[0]->Ident.token;
 				Token name_token = p->names[0]->Ident.token;
-				if (is_type_indexable(t)) {
-					bool ok = true;
-					for_array(emi, entity_map.entries) {
-						Entity *e = entity_map.entries[emi].value;
-						if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
-							if (is_type_indexable(e->type)) {
-								if (e->identifier != p->names[0]) {
-									ok = false;
-									using_index_expr = e;
-									break;
-								}
-							}
-						}
-					}
-					if (ok) {
-						using_index_expr = fields[fields.count-1];
-					} else {
-						fields[fields.count-1]->flags &= ~EntityFlag_Using;
-						error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string));
-					}
-				} else {
-					gbString type_str = type_to_string(first_type);
-					error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
-					gb_string_free(type_str);
-					continue;
-				}
+				gbString type_str = type_to_string(first_type);
+				error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
+				gb_string_free(type_str);
+				continue;
 			}
 			}
 
 
 			populate_using_entity_map(c, node, type, &entity_map);
 			populate_using_entity_map(c, node, type, &entity_map);

+ 34 - 3
src/checker.cpp

@@ -1551,18 +1551,18 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
 	}
 	}
 
 
 	Array<EntityGraphNode *> G = {};
 	Array<EntityGraphNode *> G = {};
-	array_init(&G, a);
+	array_init(&G, a, 2*M.entries.count);
 
 
 	for_array(i, M.entries) {
 	for_array(i, M.entries) {
 		auto *entry = &M.entries[i];
 		auto *entry = &M.entries[i];
-		Entity *   e = cast(Entity *)entry->key.ptr;
+		auto *e = cast(Entity *)entry->key.ptr;
 		EntityGraphNode *n = entry->value;
 		EntityGraphNode *n = entry->value;
 
 
 		if (e->kind == Entity_Procedure) {
 		if (e->kind == Entity_Procedure) {
 			// Connect each pred 'p' of 'n' with each succ 's' and from
 			// Connect each pred 'p' of 'n' with each succ 's' and from
 			// the procedure node
 			// the procedure node
 			for_array(j, n->pred.entries) {
 			for_array(j, n->pred.entries) {
-				EntityGraphNode *p = cast(EntityGraphNode *)n->pred.entries[j].ptr;
+				EntityGraphNode *p = n->pred.entries[j].ptr;
 
 
 				// Ignore self-cycles
 				// Ignore self-cycles
 				if (p != n) {
 				if (p != n) {
@@ -1594,6 +1594,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
 		GB_ASSERT(n->dep_count >= 0);
 		GB_ASSERT(n->dep_count >= 0);
 	}
 	}
 
 
+
 	return G;
 	return G;
 }
 }
 
 
@@ -3335,6 +3336,20 @@ void calculate_global_init_order(Checker *c) {
 
 
 
 
 void check_parsed_files(Checker *c) {
 void check_parsed_files(Checker *c) {
+#if 0
+	Timings timings = {};
+	timings_init(&timings, str_lit("check_parsed_files"), 16);
+	defer ({
+		timings_print_all(&timings);
+		timings_destroy(&timings);
+	});
+#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str))
+#else
+#define TIME_SECTION(str)
+#endif
+
+	TIME_SECTION("map full filepaths to scope");
+
 	add_type_info_type(c, t_invalid);
 	add_type_info_type(c, t_invalid);
 
 
 	// Map full filepaths to Scopes
 	// Map full filepaths to Scopes
@@ -3351,6 +3366,7 @@ void check_parsed_files(Checker *c) {
 		}
 		}
 	}
 	}
 
 
+	TIME_SECTION("collect entities");
 	// Collect Entities
 	// Collect Entities
 	for_array(i, c->parser->files) {
 	for_array(i, c->parser->files) {
 		AstFile *f = c->parser->files[i];
 		AstFile *f = c->parser->files[i];
@@ -3360,10 +3376,16 @@ void check_parsed_files(Checker *c) {
 		c->context = prev_context;
 		c->context = prev_context;
 	}
 	}
 
 
+	TIME_SECTION("import entities");
 	check_import_entities(c);
 	check_import_entities(c);
+
+	TIME_SECTION("check all global entities");
 	check_all_global_entities(c);
 	check_all_global_entities(c);
+
+	TIME_SECTION("init preload");
 	init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of'
 	init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of'
 
 
+	TIME_SECTION("check procedure bodies");
 	// Check procedure bodies
 	// Check procedure bodies
 	// NOTE(bill): Nested procedures bodies will be added to this "queue"
 	// NOTE(bill): Nested procedures bodies will be added to this "queue"
 	for_array(i, c->procs.entries) {
 	for_array(i, c->procs.entries) {
@@ -3397,12 +3419,16 @@ void check_parsed_files(Checker *c) {
 		check_proc_body(c, pi->token, pi->decl, pi->type, pi->body);
 		check_proc_body(c, pi->token, pi->decl, pi->type, pi->body);
 	}
 	}
 
 
+	TIME_SECTION("generate minimum dependency set");
 	c->info.minimum_dependency_set = generate_minimum_dependency_set(&c->info, c->info.entry_point);
 	c->info.minimum_dependency_set = generate_minimum_dependency_set(&c->info, c->info.entry_point);
 
 
 
 
+	TIME_SECTION("calculate global init order");
 	// Calculate initialization order of global variables
 	// Calculate initialization order of global variables
 	calculate_global_init_order(c);
 	calculate_global_init_order(c);
 
 
+
+	TIME_SECTION("add untyped expression values");
 	// Add untyped expression values
 	// Add untyped expression values
 	for_array(i, c->info.untyped.entries) {
 	for_array(i, c->info.untyped.entries) {
 		auto *entry = &c->info.untyped.entries[i];
 		auto *entry = &c->info.untyped.entries[i];
@@ -3420,6 +3446,8 @@ void check_parsed_files(Checker *c) {
 	// TODO(bill): Check for unused imports (and remove) or even warn/err
 	// TODO(bill): Check for unused imports (and remove) or even warn/err
 	// TODO(bill): Any other checks?
 	// TODO(bill): Any other checks?
 
 
+
+	TIME_SECTION("add type information");
 	// Add "Basic" type information
 	// Add "Basic" type information
 	for (isize i = 0; i < gb_count_of(basic_types)-1; i++) {
 	for (isize i = 0; i < gb_count_of(basic_types)-1; i++) {
 		Type *t = &basic_types[i];
 		Type *t = &basic_types[i];
@@ -3440,6 +3468,7 @@ void check_parsed_files(Checker *c) {
 		}
 		}
 	}
 	}
 
 
+	TIME_SECTION("check entry poiny");
 	if (!build_context.is_dll) {
 	if (!build_context.is_dll) {
 		Scope *s = c->info.init_scope;
 		Scope *s = c->info.init_scope;
 		GB_ASSERT(s != nullptr);
 		GB_ASSERT(s != nullptr);
@@ -3458,4 +3487,6 @@ void check_parsed_files(Checker *c) {
 			error(token, "Undefined entry point procedure 'main'");
 			error(token, "Undefined entry point procedure 'main'");
 		}
 		}
 	}
 	}
+
+#undef TIME_SECTION
 }
 }

+ 2 - 13
src/ir.cpp

@@ -5335,7 +5335,7 @@ bool ir_is_elem_const(irModule *m, AstNode *elem, Type *elem_type) {
 		elem = elem->FieldValue.value;
 		elem = elem->FieldValue.value;
 	}
 	}
 	TypeAndValue tav = type_and_value_of_expr(m->info, elem);
 	TypeAndValue tav = type_and_value_of_expr(m->info, elem);
-	GB_ASSERT(tav.mode != Addressing_Invalid);
+	GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type));
 	return tav.value.kind != ExactValue_Invalid;
 	return tav.value.kind != ExactValue_Invalid;
 }
 }
 
 
@@ -5517,6 +5517,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 
 
 		bool deref = is_type_pointer(t);
 		bool deref = is_type_pointer(t);
 		t = base_type(type_deref(t));
 		t = base_type(type_deref(t));
+		GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
 
 
 		if (is_type_map(t)) {
 		if (is_type_map(t)) {
 			irValue *map_val = ir_build_addr_ptr(proc, ie->expr);
 			irValue *map_val = ir_build_addr_ptr(proc, ie->expr);
@@ -5532,18 +5533,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
 		}
 		}
 
 
 		irValue *using_addr = nullptr;
 		irValue *using_addr = nullptr;
-		if (!is_type_indexable(t)) {
-			// Using index expression
-			Entity *using_field = find_using_index_expr(t);
-			if (using_field != nullptr) {
-				Selection sel = lookup_field(a, t, using_field->token.string, false);
-				irValue *e = ir_build_addr_ptr(proc, ie->expr);
-				using_addr = ir_emit_deep_field_gep(proc, e, sel);
-
-				t = using_field->type;
-			}
-		}
-
 
 
 		switch (t->kind) {
 		switch (t->kind) {
 		case Type_Vector: {
 		case Type_Vector: {

+ 0 - 2
src/ir_print.cpp

@@ -880,8 +880,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin
 			ir_print_type(f, m, t_int);
 			ir_print_type(f, m, t_int);
 			ir_write_string(f, " 0, i32 0), ");
 			ir_write_string(f, " 0, i32 0), ");
 			ir_print_type(f, m, t_int);
 			ir_print_type(f, m, t_int);
-			ir_fprintf(f, " %lld, ", cs->count);
-			ir_print_type(f, m, t_int);
 			ir_fprintf(f, " %lld}", cs->count);
 			ir_fprintf(f, " %lld}", cs->count);
 		}
 		}
 		break;
 		break;

+ 2 - 3
src/main.cpp

@@ -558,7 +558,7 @@ void show_timings(Checker *c, Timings *t) {
 	{
 	{
 		TimeStamp ts = t->sections[0];
 		TimeStamp ts = t->sections[0];
 		GB_ASSERT(ts.label == "parse files");
 		GB_ASSERT(ts.label == "parse files");
-		f64 parse_time = time_stamp_as_second(ts, t->freq);
+		f64 parse_time = time_stamp_as_s(ts, t->freq);
 		gb_printf("Parse pass\n");
 		gb_printf("Parse pass\n");
 		gb_printf("LOC/s        - %.3f\n", cast(f64)lines/parse_time);
 		gb_printf("LOC/s        - %.3f\n", cast(f64)lines/parse_time);
 		gb_printf("us/LOC       - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
 		gb_printf("us/LOC       - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
@@ -610,6 +610,7 @@ int main(int arg_count, char **arg_ptr) {
 	Timings timings = {0};
 	Timings timings = {0};
 	timings_init(&timings, str_lit("Total Time"), 128);
 	timings_init(&timings, str_lit("Total Time"), 128);
 	defer (timings_destroy(&timings));
 	defer (timings_destroy(&timings));
+
 	init_string_buffer_memory();
 	init_string_buffer_memory();
 	init_scratch_memory(gb_megabytes(10));
 	init_scratch_memory(gb_megabytes(10));
 	init_global_error_collector();
 	init_global_error_collector();
@@ -853,7 +854,6 @@ int main(int arg_count, char **arg_ptr) {
 		if (run_output) {
 		if (run_output) {
 			system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
 			system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
 		}
 		}
-
 	#else
 	#else
 
 
 		// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
 		// NOTE(zangent): Linux / Unix is unfinished and not tested very well.
@@ -993,7 +993,6 @@ int main(int arg_count, char **arg_ptr) {
 		if (run_output) {
 		if (run_output) {
 			system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
 			system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
 		}
 		}
-
 	#endif
 	#endif
 #endif
 #endif
 #endif
 #endif

+ 39 - 11
src/timings.cpp

@@ -104,16 +104,40 @@ void timings_start_section(Timings *t, String label) {
 	array_add(&t->sections, make_time_stamp(label));
 	array_add(&t->sections, make_time_stamp(label));
 }
 }
 
 
-f64 time_stamp_as_second(TimeStamp ts, u64 freq) {
+f64 time_stamp_as_s(TimeStamp const &ts, u64 freq) {
 	GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
 	GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label));
 	return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
 	return cast(f64)(ts.finish - ts.start) / cast(f64)freq;
 }
 }
 
 
-f64 time_stamp_as_ms(TimeStamp ts, u64 freq) {
-	return 1000.0*time_stamp_as_second(ts, freq);
+f64 time_stamp_as_ms(TimeStamp const &ts, u64 freq) {
+	return 1000.0*time_stamp_as_s(ts, freq);
 }
 }
 
 
-void timings_print_all(Timings *t) {
+f64 time_stamp_as_us(TimeStamp const &ts, u64 freq) {
+	return 1000000.0*time_stamp_as_s(ts, freq);
+}
+
+enum TimingUnit {
+	TimingUnit_Second,
+	TimingUnit_Millisecond,
+	TimingUnit_Microsecond,
+
+	TimingUnit_COUNT,
+};
+
+char const *timing_unit_strings[TimingUnit_COUNT] = {"s", "ms", "us"};
+
+f64 time_stamp(TimeStamp const &ts, u64 freq, TimingUnit unit) {
+	f64 total_time = 0;
+	switch (unit) {
+	case TimingUnit_Millisecond: return time_stamp_as_ms(ts, freq);
+	case TimingUnit_Microsecond: return time_stamp_as_us(ts, freq);
+	default: /*fallthrough*/
+	case TimingUnit_Second:      return time_stamp_as_s (ts, freq);
+	}
+}
+
+void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Millisecond) {
 	char const SPACES[] = "                                                                ";
 	char const SPACES[] = "                                                                ";
 	isize max_len;
 	isize max_len;
 
 
@@ -121,6 +145,7 @@ void timings_print_all(Timings *t) {
 	t->total.finish = time_stamp_time_now();
 	t->total.finish = time_stamp_time_now();
 
 
 	max_len = t->total.label.len;
 	max_len = t->total.label.len;
+	max_len = 36;
 	for_array(i, t->sections) {
 	for_array(i, t->sections) {
 		TimeStamp ts = t->sections[i];
 		TimeStamp ts = t->sections[i];
 		max_len = gb_max(max_len, ts.label.len);
 		max_len = gb_max(max_len, ts.label.len);
@@ -128,22 +153,25 @@ void timings_print_all(Timings *t) {
 
 
 	GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
 	GB_ASSERT(max_len <= gb_size_of(SPACES)-1);
 
 
-	t->total_time_seconds = time_stamp_as_second(t->total, t->freq);
+	t->total_time_seconds = time_stamp_as_s(t->total, t->freq);
 
 
-	f64 total_ms = time_stamp_as_ms(t->total, t->freq);
+	f64 total_time = time_stamp(t->total, t->freq, unit);
 
 
-	gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
+	gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
 	          LIT(t->total.label),
 	          LIT(t->total.label),
 	          cast(int)(max_len-t->total.label.len), SPACES,
 	          cast(int)(max_len-t->total.label.len), SPACES,
-	          total_ms,
+	          total_time,
+	          timing_unit_strings[unit],
 	          cast(f64)100.0);
 	          cast(f64)100.0);
 
 
 	for_array(i, t->sections) {
 	for_array(i, t->sections) {
 		TimeStamp ts = t->sections[i];
 		TimeStamp ts = t->sections[i];
-		f64 section_ms = time_stamp_as_ms(ts, t->freq);
-		gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n",
+		f64 section_time = time_stamp(ts, t->freq, unit);
+		gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
 		          LIT(ts.label),
 		          LIT(ts.label),
 	              cast(int)(max_len-ts.label.len), SPACES,
 	              cast(int)(max_len-ts.label.len), SPACES,
-		          section_ms, 100*section_ms/total_ms);
+		          section_time,
+		          timing_unit_strings[unit],
+		          100.0*section_time/total_time);
 	}
 	}
 }
 }

+ 12 - 1
src/types.cpp

@@ -950,7 +950,18 @@ bool is_type_valid_for_keys(Type *t) {
 
 
 
 
 bool is_type_indexable(Type *t) {
 bool is_type_indexable(Type *t) {
-	return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t);
+	Type *bt = base_type(t);
+	switch (bt->kind) {
+	case Type_Basic:
+		return is_type_string(bt);
+	case Type_Array:
+	case Type_Slice:
+	case Type_Vector:
+	case Type_DynamicArray:
+	case Type_Map:
+		return true;
+	}
+	return false;
 }
 }
 
 
 bool is_type_polymorphic_struct(Type *t) {
 bool is_type_polymorphic_struct(Type *t) {