aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2017-11-28 22:12:33 +0000
committergingerBill <bill@gingerbill.org>2017-11-28 22:12:33 +0000
commitcfabc0e61f2c3dc00fd367e3f9bf1a89461971ef (patch)
tree2ab0837c107e9d7f20bba979bf08865d26b59407 /src
parent91b534d128be65ee672fd21f8100a15244597604 (diff)
Remove `using` in arrays; Remove `_` non-exported struct fields
Start determining slow parts of the compiler
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp84
-rw-r--r--src/check_stmt.cpp400
-rw-r--r--src/check_type.cpp62
-rw-r--r--src/checker.cpp37
-rw-r--r--src/ir.cpp15
-rw-r--r--src/ir_print.cpp2
-rw-r--r--src/main.cpp5
-rw-r--r--src/timings.cpp50
-rw-r--r--src/types.cpp13
9 files changed, 299 insertions, 369 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 359e1e069..b65f760a7 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -2541,27 +2541,6 @@ isize entity_overload_count(Scope *s, String name) {
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) {
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) {
String field_name = selector->Ident.token.string;
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;
// 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) {
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));
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) {
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"));
}
} 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;
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) {
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);
- 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)) {
is_constant = false;
}
@@ -6032,13 +5955,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
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) {
gbString str = expr_to_string(o->expr);
gbString type_str = type_to_string(o->type);
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index bbc1aaab3..24c82545e 100644
--- a/src/check_stmt.cpp
+++ b/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);
}
-
}
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;
}
+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) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
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"));
}
}
-
case_end;
case_ast_node(fs, ForStmt, node);
@@ -1193,202 +1392,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_end;
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_ast_node(ss, TypeSwitchStmt, node);
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 7d4f8ca6e..8842596b3 100644
--- a/src/check_type.cpp
+++ b/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) {
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[0]->kind == AstNode_Ident) {
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);
@@ -408,7 +385,6 @@ Array<Entity *> check_struct_fields(Checker *c, AstNode *node, Array<AstNode *>
field_src_index += 1;
}
- Entity *using_index_expr = nullptr;
if (is_using && p->names.count > 0) {
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[0]->kind == AstNode_Ident) {
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);
diff --git a/src/checker.cpp b/src/checker.cpp
index 88ad773c0..da8ed4e7d 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1551,18 +1551,18 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
}
Array<EntityGraphNode *> G = {};
- array_init(&G, a);
+ array_init(&G, a, 2*M.entries.count);
for_array(i, M.entries) {
auto *entry = &M.entries[i];
- Entity * e = cast(Entity *)entry->key.ptr;
+ auto *e = cast(Entity *)entry->key.ptr;
EntityGraphNode *n = entry->value;
if (e->kind == Entity_Procedure) {
// Connect each pred 'p' of 'n' with each succ 's' and from
// the procedure node
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
if (p != n) {
@@ -1594,6 +1594,7 @@ Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInfo *info) {
GB_ASSERT(n->dep_count >= 0);
}
+
return G;
}
@@ -3335,6 +3336,20 @@ void calculate_global_init_order(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);
// Map full filepaths to Scopes
@@ -3351,6 +3366,7 @@ void check_parsed_files(Checker *c) {
}
}
+ TIME_SECTION("collect entities");
// Collect Entities
for_array(i, c->parser->files) {
AstFile *f = c->parser->files[i];
@@ -3360,10 +3376,16 @@ void check_parsed_files(Checker *c) {
c->context = prev_context;
}
+ TIME_SECTION("import entities");
check_import_entities(c);
+
+ TIME_SECTION("check all global entities");
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'
+ TIME_SECTION("check procedure bodies");
// Check procedure bodies
// NOTE(bill): Nested procedures bodies will be added to this "queue"
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);
}
+ TIME_SECTION("generate minimum dependency set");
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_global_init_order(c);
+
+ TIME_SECTION("add untyped expression values");
// Add untyped expression values
for_array(i, c->info.untyped.entries) {
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): Any other checks?
+
+ TIME_SECTION("add type information");
// Add "Basic" type information
for (isize i = 0; i < gb_count_of(basic_types)-1; 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) {
Scope *s = c->info.init_scope;
GB_ASSERT(s != nullptr);
@@ -3458,4 +3487,6 @@ void check_parsed_files(Checker *c) {
error(token, "Undefined entry point procedure 'main'");
}
}
+
+#undef TIME_SECTION
}
diff --git a/src/ir.cpp b/src/ir.cpp
index b8efb563e..3128bfd5d 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5335,7 +5335,7 @@ bool ir_is_elem_const(irModule *m, AstNode *elem, Type *elem_type) {
elem = elem->FieldValue.value;
}
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;
}
@@ -5517,6 +5517,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
bool deref = is_type_pointer(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)) {
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;
- 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) {
case Type_Vector: {
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 0b0e5d97b..40346075a 100644
--- a/src/ir_print.cpp
+++ b/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_write_string(f, " 0, i32 0), ");
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);
}
break;
diff --git a/src/main.cpp b/src/main.cpp
index eff12cc40..6dd5ad1f9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -558,7 +558,7 @@ void show_timings(Checker *c, Timings *t) {
{
TimeStamp ts = t->sections[0];
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("LOC/s - %.3f\n", cast(f64)lines/parse_time);
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_init(&timings, str_lit("Total Time"), 128);
defer (timings_destroy(&timings));
+
init_string_buffer_memory();
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
@@ -853,7 +854,6 @@ int main(int arg_count, char **arg_ptr) {
if (run_output) {
system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base));
}
-
#else
// 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) {
system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base));
}
-
#endif
#endif
#endif
diff --git a/src/timings.cpp b/src/timings.cpp
index 5422fd212..a5d6296a7 100644
--- a/src/timings.cpp
+++ b/src/timings.cpp
@@ -104,16 +104,40 @@ void timings_start_section(Timings *t, String 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));
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[] = " ";
isize max_len;
@@ -121,6 +145,7 @@ void timings_print_all(Timings *t) {
t->total.finish = time_stamp_time_now();
max_len = t->total.label.len;
+ max_len = 36;
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
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);
- 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),
cast(int)(max_len-t->total.label.len), SPACES,
- total_ms,
+ total_time,
+ timing_unit_strings[unit],
cast(f64)100.0);
for_array(i, t->sections) {
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),
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);
}
}
diff --git a/src/types.cpp b/src/types.cpp
index 8dae03451..225f01bd8 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -950,7 +950,18 @@ bool is_type_valid_for_keys(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) {