aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.cpp171
-rw-r--r--src/check_expr.cpp305
-rw-r--r--src/check_stmt.cpp364
-rw-r--r--src/check_type.cpp382
-rw-r--r--src/checker.cpp310
-rw-r--r--src/checker.hpp38
-rw-r--r--src/ir.cpp14
7 files changed, 799 insertions, 785 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index acfb3140d..42b578605 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -1,8 +1,8 @@
bool check_is_terminating(AstNode *node);
-void check_stmt (Checker *c, AstNode *node, u32 flags);
+void check_stmt (CheckerContext *ctx, AstNode *node, u32 flags);
// NOTE(bill): 'content_name' is for debugging and error messages
-Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
+Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
@@ -27,7 +27,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string));
} else {
- check_assignment(c, operand, e->type, str_lit("variable assignment"));
+ check_assignment(ctx, operand, e->type, str_lit("variable assignment"));
if (operand->mode != Addressing_Type) {
return operand->type;
}
@@ -79,9 +79,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
e->type = t;
}
- e->parent_proc_decl = c->context.curr_proc_decl;
+ e->parent_proc_decl = ctx->curr_proc_decl;
- check_assignment(c, operand, e->type, context_name);
+ check_assignment(ctx, operand, e->type, context_name);
if (operand->mode == Addressing_Invalid) {
return nullptr;
}
@@ -89,7 +89,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
return e->type;
}
-void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
+void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return;
}
@@ -97,9 +97,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
- auto operands = array_make<Operand>(c->allocator, 0, 2*lhs_count);
+ auto operands = array_make<Operand>(ctx->allocator, 0, 2*lhs_count);
defer (array_free(&operands));
- check_unpack_arguments(c, lhs, lhs_count, &operands, inits, true);
+ check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true);
isize rhs_count = operands.count;
for_array(i, operands) {
@@ -111,9 +111,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
Entity *e = lhs[i];
- DeclInfo *d = decl_info_of_entity(&c->info, e);
+ DeclInfo *d = decl_info_of_entity(&ctx->checker->info, e);
Operand *o = &operands[i];
- check_init_variable(c, e, o, context_name);
+ check_init_variable(ctx, e, o, context_name);
if (d != nullptr) {
d->init_expr = o->expr;
}
@@ -123,7 +123,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
}
}
-void check_init_constant(Checker *c, Entity *e, Operand *operand) {
+void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
@@ -157,12 +157,12 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
e->type = operand->type;
}
- check_assignment(c, operand, e->type, str_lit("constant declaration"));
+ check_assignment(ctx, operand, e->type, str_lit("constant declaration"));
if (operand->mode == Addressing_Invalid) {
return;
}
- e->parent_proc_decl = c->context.curr_proc_decl;
+ e->parent_proc_decl = ctx->curr_proc_decl;
e->Constant.value = operand->value;
}
@@ -217,10 +217,10 @@ AstNode *remove_type_alias_clutter(AstNode *node) {
}
}
-void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
+void check_type_decl(CheckerContext *ctx, Entity *e, AstNode *type_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
- DeclInfo *decl = decl_info_of_entity(&c->info, e);
+ DeclInfo *decl = decl_info_of_entity(&ctx->checker->info, e);
if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on type declarations");
}
@@ -238,9 +238,9 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
}
e->type = named;
- check_type_path_push(c, e);
- Type *bt = check_type_expr(c, te, named);
- check_type_path_pop(c);
+ check_type_path_push(ctx, e);
+ Type *bt = check_type_expr(ctx, te, named);
+ check_type_path_pop(ctx);
named->Named.base = base_type(bt);
if (!is_distinct) {
@@ -260,7 +260,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
// }
}
-void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
+void check_const_decl(CheckerContext *ctx, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Constant);
@@ -271,7 +271,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
e->flags |= EntityFlag_Visited;
if (type_expr) {
- Type *t = check_type(c, type_expr);
+ Type *t = check_type(ctx, type_expr);
if (!is_type_constant_type(t)) {
gbString str = type_to_string(t);
error(type_expr, "Invalid constant type '%s'", str);
@@ -287,11 +287,11 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
if (init != nullptr) {
Entity *entity = nullptr;
if (init->kind == AstNode_Ident) {
- entity = check_ident(c, &operand, init, nullptr, e->type, true);
+ entity = check_ident(ctx, &operand, init, nullptr, e->type, true);
} else if (init->kind == AstNode_SelectorExpr) {
- entity = check_selector(c, &operand, init, e->type);
+ entity = check_selector(ctx, &operand, init, e->type);
} else {
- check_expr_or_type(c, &operand, init, e->type);
+ check_expr_or_type(ctx, &operand, init, e->type);
}
switch (operand.mode) {
@@ -299,12 +299,12 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
e->kind = Entity_TypeName;
e->type = nullptr;
- DeclInfo *d = c->context.decl;
+ DeclInfo *d = ctx->decl;
if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter");
}
d->type_expr = d->init_expr;
- check_type_decl(c, e, d->type_expr, named_type);
+ check_type_decl(ctx, e, d->type_expr, named_type);
return;
}
@@ -360,10 +360,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
if (init != nullptr) {
- check_expr_or_type(c, &operand, init, e->type);
+ check_expr_or_type(ctx, &operand, init, e->type);
}
- check_init_constant(c, e, &operand);
+ check_init_constant(ctx, e, &operand);
if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_invalid) {
@@ -373,7 +373,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
- DeclInfo *decl = decl_info_of_entity(&c->info, e);
+ DeclInfo *decl = decl_info_of_entity(&ctx->checker->info, e);
if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on constant value declarations");
}
@@ -433,7 +433,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
return true;
}
-void init_entity_foreign_library(Checker *c, Entity *e) {
+void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
AstNode *ident = nullptr;
Entity **foreign_library = nullptr;
@@ -456,7 +456,7 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
error(ident, "foreign library names must be an identifier");
} else {
String name = ident->Ident.token.string;
- Entity *found = scope_lookup_entity(c->context.scope, name);
+ Entity *found = scope_lookup_entity(ctx->scope, name);
if (found == nullptr) {
if (is_blank_ident(name)) {
error(ident, "'_' cannot be used as a value type");
@@ -469,18 +469,18 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
// TODO(bill): Extra stuff to do with library names?
*foreign_library = found;
found->LibraryName.used = true;
- add_entity_use(c, ident, found);
+ add_entity_use(ctx, ident, found);
}
}
}
-String handle_link_name(Checker *c, Token token, String link_name, String link_prefix) {
+String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
if (link_prefix.len > 0) {
if (link_name.len > 0) {
error(token, "'link_name' and 'link_prefix' cannot be used together");
} else {
isize len = link_prefix.len + token.string.len;
- u8 *name = gb_alloc_array(c->allocator, u8, len+1);
+ u8 *name = gb_alloc_array(ctx->allocator, u8, len+1);
gb_memmove(name, &link_prefix[0], link_prefix.len);
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
name[len] = 0;
@@ -491,7 +491,7 @@ String handle_link_name(Checker *c, Token token, String link_name, String link_p
return link_name;
}
-void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
+void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message
@@ -508,14 +508,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
e->type = proc_type;
ast_node(pl, ProcLit, d->proc_lit);
- check_open_scope(c, pl->type);
- defer (check_close_scope(c));
+ check_open_scope(ctx, pl->type);
+ defer (check_close_scope(ctx));
- auto prev_context = c->context;
- c->context.allow_polymorphic_types = true;
- check_procedure_type(c, proc_type, pl->type);
- c->context = prev_context;
+ auto tmp_ctx = *ctx;
+ tmp_ctx.allow_polymorphic_types = true;
+ check_procedure_type(&tmp_ctx, proc_type, pl->type);
TypeProc *pt = &proc_type->Proc;
@@ -526,11 +525,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
if (d != nullptr) {
- check_decl_attributes(c, d->attributes, proc_decl_attribute, &ac);
+ check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
}
e->deprecated_message = ac.deprecated_message;
- ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
+ ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
if (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 ||
@@ -545,10 +544,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
pt->calling_convention = ProcCC_Contextless;
if (e->pkg->kind == Package_Init) {
- if (c->info.entry_point != nullptr) {
+ if (ctx->checker->info.entry_point != nullptr) {
error(e->token, "Redeclaration of the entry pointer procedure 'main'");
} else {
- c->info.entry_point = e;
+ ctx->checker->info.entry_point = e;
}
}
}
@@ -576,11 +575,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
error(pl->body, "A procedure with a '#c_vararg' field cannot have a body and must be foreign");
}
- d->scope = c->context.scope;
+ d->scope = ctx->scope;
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
if (!pt->is_polymorphic) {
- check_procedure_later(c, c->context.file, e->token, d, proc_type, pl->body, pl->tags);
+ check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
}
} else if (!is_foreign) {
if (e->Procedure.is_export) {
@@ -608,9 +607,9 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
e->Procedure.is_foreign = true;
e->Procedure.link_name = name;
- init_entity_foreign_library(c, e);
+ init_entity_foreign_library(ctx, e);
- auto *fp = &c->info.foreigns;
+ auto *fp = &ctx->checker->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
@@ -642,7 +641,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
name = e->Procedure.link_name;
}
if (e->Procedure.link_name.len > 0 || is_export) {
- auto *fp = &c->info.foreigns;
+ auto *fp = &ctx->checker->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
@@ -662,7 +661,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
}
}
-void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array<AstNode *> init_expr_list) {
+void check_var_decl(CheckerContext *ctx, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array<AstNode *> init_expr_list) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
@@ -675,18 +674,18 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
ac.init_expr_list_count = init_expr_list.count;
- DeclInfo *decl = decl_info_of_entity(&c->info, e);
+ DeclInfo *decl = decl_info_of_entity(&ctx->checker->info, e);
if (decl != nullptr) {
- check_decl_attributes(c, decl->attributes, var_decl_attribute, &ac);
+ check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
}
- ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
+ ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
String context_name = str_lit("variable declaration");
if (type_expr != nullptr) {
- e->type = check_type(c, type_expr);
+ e->type = check_type(ctx, type_expr);
}
if (e->type != nullptr) {
if (is_type_polymorphic(base_type(e->type))) {
@@ -707,7 +706,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
if (init_expr_list.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
- init_entity_foreign_library(c, e);
+ init_entity_foreign_library(ctx, e);
}
if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name;
@@ -718,7 +717,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
if (e->Variable.link_name.len > 0) {
name = e->Variable.link_name;
}
- auto *fp = &c->info.foreigns;
+ auto *fp = &ctx->checker->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
@@ -750,17 +749,17 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
}
- check_init_variables(c, entities, entity_count, init_expr_list, context_name);
+ check_init_variables(ctx, entities, entity_count, init_expr_list, context_name);
}
-void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
+void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) {
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
auto *pge = &pg_entity->ProcGroup;
String proc_group_name = pg_entity->token.string;
ast_node(pg, ProcGroup, d->init_expr);
- pge->entities = array_make<Entity*>(c->allocator, 0, pg->args.count);
+ pge->entities = array_make<Entity*>(ctx->allocator, 0, pg->args.count);
// NOTE(bill): This must be set here to prevent cycles in checking if someone
// places the entity within itself
@@ -775,9 +774,9 @@ void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
Entity *e = nullptr;
Operand o = {};
if (arg->kind == AstNode_Ident) {
- e = check_ident(c, &o, arg, nullptr, nullptr, true);
+ e = check_ident(ctx, &o, arg, nullptr, nullptr, true);
} else if (arg->kind == AstNode_SelectorExpr) {
- e = check_selector(c, &o, arg, nullptr);
+ e = check_selector(ctx, &o, arg, nullptr);
}
if (e == nullptr) {
error(arg, "Expected a valid entity name in procedure group, got %.*s", LIT(ast_node_strings[arg->kind]));
@@ -865,7 +864,7 @@ void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
}
-void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
+void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
if (e->state == EntityState_Resolved) {
return;
}
@@ -893,7 +892,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
#endif
if (d == nullptr) {
- d = decl_info_of_entity(&c->info, e);
+ d = decl_info_of_entity(&ctx->checker->info, e);
if (d == nullptr) {
// TODO(bill): Err here?
e->type = t_invalid;
@@ -904,43 +903,41 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
}
}
- CheckerContext prev = c->context;
- c->context.scope = d->scope;
- c->context.decl = d;
- c->context.type_level = 0;
+ CheckerContext c = *ctx;
+ c.scope = d->scope;
+ c.decl = d;
+ c.type_level = 0;
- e->parent_proc_decl = c->context.curr_proc_decl;
+ e->parent_proc_decl = c.curr_proc_decl;
e->state = EntityState_InProgress;
switch (e->kind) {
case Entity_Variable:
- check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list);
+ check_var_decl(&c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list);
break;
case Entity_Constant:
- check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
+ check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
break;
case Entity_TypeName: {
- check_type_decl(c, e, d->type_expr, named_type);
+ check_type_decl(&c, e, d->type_expr, named_type);
break;
}
case Entity_Procedure:
- check_proc_decl(c, e, d);
+ check_proc_decl(&c, e, d);
break;
case Entity_ProcGroup:
- check_proc_group_decl(c, e, d);
+ check_proc_group_decl(&c, e, d);
break;
}
e->state = EntityState_Resolved;
- c->context = prev;
-
#undef TIME_SECTION
}
-void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
+void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, AstNode *body) {
if (body == nullptr) {
return;
}
@@ -954,14 +951,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
proc_name = str_lit("(anonymous-procedure)");
}
- CheckerContext old_context = c->context;
- defer (c->context = old_context);
+ CheckerContext new_ctx = *ctx_;
+ CheckerContext *ctx = &new_ctx;
- c->context.scope = decl->scope;
- c->context.decl = decl;
- c->context.proc_name = proc_name;
- c->context.curr_proc_decl = decl;
- c->context.curr_proc_sig = type;
+ ctx->scope = decl->scope;
+ ctx->decl = decl;
+ ctx->proc_name = proc_name;
+ ctx->curr_proc_decl = decl;
+ ctx->curr_proc_sig = type;
GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) {
@@ -981,7 +978,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
if (scope == nullptr) {
- scope = scope_of_node(&c->info, t->Struct.node);
+ scope = scope_of_node(&ctx->checker->info, t->Struct.node);
}
GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) {
@@ -991,7 +988,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
uvar->Variable.is_immutable = is_immutable;
if (is_value) uvar->flags |= EntityFlag_Value;
- Entity *prev = scope_insert_entity(c->context.scope, uvar);
+ Entity *prev = scope_insert_entity(ctx->scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
break;
@@ -1006,7 +1003,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
}
ast_node(bs, BlockStmt, body);
- check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
+ check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
if (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) {
@@ -1017,7 +1014,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
}
}
- check_scope_usage(c, c->context.scope);
+ check_scope_usage(ctx->checker, ctx->scope);
if (decl->parent != nullptr) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 78f682884..181de0654 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -45,41 +45,41 @@ int valid_index_and_score_cmp(void const *a, void const *b) {
-#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Entity *entity, Array<Operand> operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
+#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, AstNode *call, Type *proc_type, Entity *entity, Array<Operand> operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
-void check_expr (Checker *c, Operand *operand, AstNode *expression);
-void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
-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 * check_type_expr (Checker *c, AstNode *expression, Type *named_type);
+void check_expr (CheckerContext *c, Operand *operand, AstNode *expression);
+void check_multi_expr (CheckerContext *c, Operand *operand, AstNode *expression);
+void check_expr_or_type (CheckerContext *c, Operand *operand, AstNode *expression, Type *type_hint = nullptr);
+ExprKind check_expr_base (CheckerContext *c, Operand *operand, AstNode *expression, Type *type_hint);
+void check_expr_with_type_hint (CheckerContext *c, Operand *o, AstNode *e, Type *t);
+Type * check_type (CheckerContext *c, AstNode *expression);
+Type * check_type_expr (CheckerContext *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);
-Entity * check_ident (Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name);
-Entity * find_polymorphic_struct_entity (Checker *c, Type *original_type, isize param_count, Array<Operand> ordered_operands);
-void check_not_tuple (Checker *c, Operand *operand);
-void convert_to_typed (Checker *c, Operand *operand, Type *target_type);
+void check_type_decl (CheckerContext *c, Entity *e, AstNode *type_expr, Type *def);
+Entity * check_selector (CheckerContext *c, Operand *operand, AstNode *node, Type *type_hint);
+Entity * check_ident (CheckerContext *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name);
+Entity * find_polymorphic_struct_entity (CheckerContext *c, Type *original_type, isize param_count, Array<Operand> ordered_operands);
+void check_not_tuple (CheckerContext *c, Operand *operand);
+void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type);
gbString expr_to_string (AstNode *expression);
-void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type);
-void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
-void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
-void update_expr_type (Checker *c, AstNode *e, Type *type, bool final);
+void check_entity_decl (CheckerContext *c, Entity *e, DeclInfo *decl, Type *named_type);
+void check_const_decl (CheckerContext *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
+void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
+void update_expr_type (CheckerContext *c, AstNode *e, Type *type, bool final);
bool check_is_terminating (AstNode *node);
bool check_has_break (AstNode *stmt, bool implicit);
-void check_stmt (Checker *c, AstNode *node, u32 flags);
-void check_stmt_list (Checker *c, Array<AstNode *> stmts, u32 flags);
-void check_init_constant (Checker *c, Entity *e, Operand *operand);
-bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
-bool check_procedure_type (Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands = nullptr);
-void check_struct_type (Checker *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands,
+void check_stmt (CheckerContext *c, AstNode *node, u32 flags);
+void check_stmt_list (CheckerContext *c, Array<AstNode *> stmts, u32 flags);
+void check_init_constant (CheckerContext *c, Entity *e, Operand *operand);
+bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value);
+bool check_procedure_type (CheckerContext *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands = nullptr);
+void check_struct_type (CheckerContext *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands,
Type *named_type = nullptr, Type *original_type_for_poly = nullptr);
-CallArgumentData check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call);
-Type * check_init_variable (Checker *c, Entity *e, Operand *operand, String context_name);
+CallArgumentData check_call_arguments (CheckerContext *c, Operand *operand, Type *proc_type, AstNode *call);
+Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name);
@@ -107,8 +107,8 @@ void error_operand_no_value(Operand *o) {
}
-void check_scope_decls(Checker *c, Array<AstNode *> nodes, isize reserve_size) {
- Scope *s = c->context.scope;
+void check_scope_decls(CheckerContext *c, Array<AstNode *> nodes, isize reserve_size) {
+ Scope *s = c->scope;
GB_ASSERT(s->package == nullptr);
check_collect_entities(c, nodes);
@@ -123,7 +123,7 @@ void check_scope_decls(Checker *c, Array<AstNode *> nodes, isize reserve_size) {
default:
continue;
}
- DeclInfo *d = decl_info_of_entity(&c->info, e);
+ DeclInfo *d = decl_info_of_entity(&c->checker->info, e);
if (d != nullptr) {
check_entity_decl(c, e, d, nullptr);
}
@@ -165,7 +165,7 @@ bool check_is_assignable_to_using_subtype(Type *src, Type *dst) {
return false;
}
-bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Type *type,
+bool find_or_generate_polymorphic_procedure(CheckerContext *c, Entity *base_entity, Type *type,
Array<Operand> *param_operands, PolyProcData *poly_proc_data) {
///////////////////////////////////////////////////////////////////////////////
// //
@@ -211,7 +211,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
}
- DeclInfo *old_decl = decl_info_of_entity(&c->info, base_entity);
+ DeclInfo *old_decl = decl_info_of_entity(&c->checker->info, base_entity);
if (old_decl == nullptr) {
return false;
}
@@ -239,39 +239,38 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
+ CheckerContext nctx = *c;
Scope *scope = create_scope(base_entity->scope, a);
scope->is_proc = true;
- c->context.scope = scope;
- c->context.allow_polymorphic_types = true;
- if (c->context.polymorphic_scope == nullptr) {
- c->context.polymorphic_scope = scope;
+ nctx.scope = scope;
+ nctx.allow_polymorphic_types = true;
+ if (nctx.polymorphic_scope == nullptr) {
+ nctx.polymorphic_scope = scope;
}
if (param_operands == nullptr) {
- // c->context.no_polymorphic_errors = false;
+ // c->no_polymorphic_errors = false;
}
- bool generate_type_again = c->context.no_polymorphic_errors;
+ bool generate_type_again = nctx.no_polymorphic_errors;
auto *pt = &src->Proc;
// NOTE(bill): This is slightly memory leaking if the type already exists
// Maybe it's better to check with the previous types first?
Type *final_proc_type = alloc_type_proc(scope, nullptr, 0, nullptr, 0, false, pt->calling_convention);
- bool success = check_procedure_type(c, final_proc_type, pt->node, &operands);
+ bool success = check_procedure_type(&nctx, final_proc_type, pt->node, &operands);
if (!success) {
return false;
}
- gb_mutex_lock(&c->mutex);
- defer (gb_mutex_unlock(&c->mutex));
+ gb_mutex_lock(&nctx.checker->mutex);
+ defer (gb_mutex_unlock(&nctx.checker->mutex));
- auto *found_gen_procs = map_get(&c->info.gen_procs, hash_pointer(base_entity->identifier));
+ auto *found_gen_procs = map_get(&nctx.checker->info.gen_procs, hash_pointer(base_entity->identifier));
if (found_gen_procs) {
auto procs = *found_gen_procs;
for_array(i, procs) {
@@ -289,14 +288,14 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
if (generate_type_again) {
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice
- bool prev_no_polymorphic_errors = c->context.no_polymorphic_errors;
- defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors);
- c->context.no_polymorphic_errors = false;
+ bool prev_no_polymorphic_errors = nctx.no_polymorphic_errors;
+ defer (nctx.no_polymorphic_errors = prev_no_polymorphic_errors);
+ nctx.no_polymorphic_errors = false;
// NOTE(bill): Reset scope from the failed procedure type
scope_reset(scope);
- success = check_procedure_type(c, final_proc_type, pt->node, &operands);
+ success = check_procedure_type(&nctx, final_proc_type, pt->node, &operands);
if (!success) {
return false;
@@ -322,25 +321,25 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit);
ast_node(pl, ProcLit, proc_lit);
// NOTE(bill): Associate the scope declared above withinth this procedure declaration's type
- add_scope(c, pl->type, final_proc_type->Proc.scope);
+ add_scope(&nctx, pl->type, final_proc_type->Proc.scope);
final_proc_type->Proc.is_poly_specialized = true;
final_proc_type->Proc.is_polymorphic = true;
u64 tags = base_entity->Procedure.tags;
AstNode *ident = clone_ast_node(a, base_entity->identifier);
Token token = ident->Ident.token;
- DeclInfo *d = make_decl_info(c->allocator, scope, old_decl->parent);
+ DeclInfo *d = make_decl_info(nctx.allocator, scope, old_decl->parent);
d->gen_proc_type = final_proc_type;
d->type_expr = pl->type;
d->proc_lit = proc_lit;
-
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
entity->identifier = ident;
- add_entity_and_decl_info(c, ident, entity, d);
+ add_entity_and_decl_info(&nctx, ident, entity, d);
// NOTE(bill): Set the scope afterwards as this is not real overloading
entity->scope = scope->parent;
+ entity->pkg = base_entity->pkg;
AstFile *file = nullptr;
{
@@ -365,7 +364,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
} else {
auto array = array_make<Entity *>(heap_allocator());
array_add(&array, entity);
- map_set(&c->info.gen_procs, hash_pointer(base_entity->identifier), array);
+ map_set(&nctx.checker->info.gen_procs, hash_pointer(base_entity->identifier), array);
}
GB_ASSERT(entity != nullptr);
@@ -376,27 +375,27 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
}
// NOTE(bill): Check the newly generated procedure body
- check_procedure_later(c, proc_info);
+ check_procedure_later(nctx.checker, proc_info);
return true;
}
-bool check_polymorphic_procedure_assignment(Checker *c, Operand *operand, Type *type, PolyProcData *poly_proc_data) {
+bool check_polymorphic_procedure_assignment(CheckerContext *c, Operand *operand, Type *type, PolyProcData *poly_proc_data) {
if (operand->expr == nullptr) return false;
- Entity *base_entity = entity_of_ident(&c->info, operand->expr);
+ Entity *base_entity = entity_of_ident(&c->checker->info, operand->expr);
if (base_entity == nullptr) return false;
return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data);
}
-bool find_or_generate_polymorphic_procedure_from_parameters(Checker *c, Entity *base_entity, Array<Operand> *operands, PolyProcData *poly_proc_data) {
+bool find_or_generate_polymorphic_procedure_from_parameters(CheckerContext *c, Entity *base_entity, Array<Operand> *operands, PolyProcData *poly_proc_data) {
return find_or_generate_polymorphic_procedure(c, base_entity, nullptr, operands, poly_proc_data);
}
-bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type);
-bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type);
-bool check_cast_internal(Checker *c, Operand *x, Type *type);
+bool check_type_specialization_to(CheckerContext *c, Type *specialization, Type *type, bool compound, bool modify_type);
+bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type);
+bool check_cast_internal(CheckerContext *c, Operand *x, Type *type);
-i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
+i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) {
if (operand->mode == Addressing_Invalid ||
type == t_invalid) {
return -1;
@@ -529,7 +528,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
#endif
if (is_type_polymorphic(dst) && !is_type_polymorphic(src)) {
- bool modify_type = !c->context.no_polymorphic_errors;
+ bool modify_type = !c->no_polymorphic_errors;
if (is_polymorphic_type_assignable(c, type, s, false, modify_type)) {
return 2;
}
@@ -595,7 +594,7 @@ i64 assign_score_function(i64 distance) {
}
-bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score_) {
+bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_) {
i64 score = 0;
i64 distance = check_distance_between_types(c, operand, type);
bool ok = distance >= 0;
@@ -607,14 +606,14 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
}
-bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
+bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) {
i64 score = 0;
return check_is_assignable_to_with_score(c, operand, type, &score);
}
// NOTE(bill): 'content_name' is for debugging and error messages
-void check_assignment(Checker *c, Operand *operand, Type *type, String context_name) {
+void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) {
check_not_tuple(c, operand);
if (operand->mode == Addressing_Invalid) {
return;
@@ -742,7 +741,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
}
}
-bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type) {
+bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type) {
Operand o = {Addressing_Value};
o.type = source;
switch (poly->kind) {
@@ -903,17 +902,17 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
return false;
}
-bool check_cycle(Checker *c, Entity *curr, bool report) {
+bool check_cycle(CheckerContext *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];
+ for_array(i, *c->type_path) {
+ Entity *prev = (*c->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];
+ for (isize j = i; j < c->type_path->count; j++) {
+ Entity *curr = (*c->type_path)[j];
error(curr->token, "\t%.*s refers to", LIT(curr->token.string));
}
error(curr->token, "\t%.*s", LIT(curr->token.string));
@@ -925,13 +924,13 @@ bool check_cycle(Checker *c, Entity *curr, bool report) {
}
-Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
+Entity *check_ident(CheckerContext *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
GB_ASSERT(n->kind == AstNode_Ident);
o->mode = Addressing_Invalid;
o->expr = n;
String name = n->Ident.token.string;
- Entity *e = scope_lookup_entity(c->context.scope, name);
+ Entity *e = scope_lookup_entity(c->scope, name);
if (e == nullptr) {
if (is_blank_ident(name)) {
error(n, "'_' cannot be used as a value type");
@@ -946,7 +945,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
return nullptr;
}
if (e->parent_proc_decl != nullptr &&
- e->parent_proc_decl != c->context.curr_proc_decl) {
+ e->parent_proc_decl != c->curr_proc_decl) {
if (e->kind == Entity_Variable) {
error(n, "Nested procedures do not capture its parent's variables: %.*s", LIT(name));
return nullptr;
@@ -967,7 +966,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
if (e->kind == Entity_ProcGroup) {
auto *pge = &e->ProcGroup;
- DeclInfo *d = decl_info_of_entity(&c->info, e);
+ DeclInfo *d = decl_info_of_entity(&c->checker->info, e);
check_entity_decl(c, e, d, nullptr);
@@ -1087,7 +1086,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
}
-bool check_unary_op(Checker *c, Operand *o, Token op) {
+bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
if (o->type == nullptr) {
gbString str = expr_to_string(o->expr);
error(o->expr, "Expression has no value '%s'", str);
@@ -1129,7 +1128,7 @@ bool check_unary_op(Checker *c, Operand *o, Token op) {
return true;
}
-bool check_binary_op(Checker *c, Operand *o, Token op) {
+bool check_binary_op(CheckerContext *c, Operand *o, Token op) {
// TODO(bill): Handle errors correctly
Type *type = base_type(core_array_type(o->type));
switch (op.kind) {
@@ -1225,7 +1224,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
}
-bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) {
+bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value) {
if (in_value.kind == ExactValue_Invalid) {
// NOTE(bill): There's already been an error
return true;
@@ -1340,7 +1339,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
return false;
}
-void check_is_expressible(Checker *c, Operand *o, Type *type) {
+void check_is_expressible(CheckerContext *c, Operand *o, Type *type) {
GB_ASSERT(is_type_constant_type(type));
GB_ASSERT(o->mode == Addressing_Constant);
if (!check_representable_as_constant(c, o->value, type, &o->value)) {
@@ -1370,14 +1369,14 @@ void check_is_expressible(Checker *c, Operand *o, Type *type) {
}
}
-bool check_is_not_addressable(Checker *c, Operand *o) {
+bool check_is_not_addressable(CheckerContext *c, Operand *o) {
if (o->mode == Addressing_OptionalOk) {
AstNode *expr = unselector_expr(o->expr);
if (expr->kind != AstNode_TypeAssertion) {
return true;
}
ast_node(ta, TypeAssertion, expr);
- TypeAndValue tv = type_and_value_of_expr(&c->info, ta->expr);
+ TypeAndValue tv = type_and_value_of_expr(&c->checker->info, ta->expr);
if (is_type_pointer(tv.type)) {
return false;
}
@@ -1400,7 +1399,7 @@ bool check_is_not_addressable(Checker *c, Operand *o) {
return false;
}
-void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
+void check_unary_expr(CheckerContext *c, Operand *o, Token op, AstNode *node) {
switch (op.kind) {
case Token_And: { // Pointer address
if (check_is_not_addressable(c, o)) {
@@ -1471,7 +1470,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
}
-void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
+void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) {
if (x->mode == Addressing_Type && y->mode == Addressing_Type) {
bool comp = are_types_identical(x->type, y->type);
switch (op) {
@@ -1585,7 +1584,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
}
-void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
+void check_shift(CheckerContext *c, Operand *x, Operand *y, AstNode *node) {
GB_ASSERT(node->kind == AstNode_BinaryExpr);
ast_node(be, BinaryExpr, node);
@@ -1656,7 +1655,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
TokenPos pos = ast_node_token(x->expr).pos;
if (x_is_untyped) {
- ExprInfo *info = check_get_expr_info(&c->info, x->expr);
+ ExprInfo *info = check_get_expr_info(&c->checker->info, x->expr);
if (info != nullptr) {
info->is_lhs = true;
}
@@ -1684,7 +1683,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
}
-Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) {
+Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) {
GB_ASSERT(node->kind == AstNode_BinaryExpr);
ast_node(be, BinaryExpr, node);
GB_ASSERT(is_type_pointer(ptr->type));
@@ -1741,7 +1740,7 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
-bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
+bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (check_is_assignable_to(c, operand, y)) {
return true;
}
@@ -1865,7 +1864,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
return false;
}
-bool check_cast_internal(Checker *c, Operand *x, Type *type) {
+bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
bool is_const_expr = x->mode == Addressing_Constant;
bool can_convert = false;
@@ -1890,7 +1889,7 @@ bool check_cast_internal(Checker *c, Operand *x, Type *type) {
}
-void check_cast(Checker *c, Operand *x, Type *type) {
+void check_cast(CheckerContext *c, Operand *x, Type *type) {
if (!is_operand_value(*x)) {
error(x->expr, "Only values can be casted");
x->mode = Addressing_Invalid;
@@ -1924,7 +1923,7 @@ void check_cast(Checker *c, Operand *x, Type *type) {
x->type = type;
}
-bool check_transmute(Checker *c, AstNode *node, Operand *o, Type *t) {
+bool check_transmute(CheckerContext *c, AstNode *node, Operand *o, Type *t) {
if (!is_operand_value(*o)) {
error(o->expr, "'transmute' can only be applied to values");
o->mode = Addressing_Invalid;
@@ -1967,7 +1966,7 @@ bool check_transmute(Checker *c, AstNode *node, Operand *o, Type *t) {
return true;
}
-bool check_binary_array_expr(Checker *c, Token op, Operand *x, Operand *y) {
+bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y) {
if (is_type_array(x->type) && !is_type_array(y->type)) {
if (check_is_assignable_to(c, y, x->type)) {
if (check_binary_op(c, x, op)) {
@@ -1979,7 +1978,7 @@ bool check_binary_array_expr(Checker *c, Token op, Operand *x, Operand *y) {
}
-void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
+void check_binary_expr(CheckerContext *c, Operand *x, AstNode *node) {
GB_ASSERT(node->kind == AstNode_BinaryExpr);
Operand y_ = {}, *y = &y_;
@@ -2167,8 +2166,8 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
}
-void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
- ExprInfo *found = check_get_expr_info(&c->info, e);
+void update_expr_type(CheckerContext *c, AstNode *e, Type *type, bool final) {
+ ExprInfo *found = check_get_expr_info(&c->checker->info, e);
if (found == nullptr) {
return;
}
@@ -2207,12 +2206,12 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
if (!final && is_type_untyped(type)) {
old.type = base_type(type);
- check_set_expr_info(&c->info, e, old);
+ check_set_expr_info(&c->checker->info, e, old);
return;
}
// We need to remove it and then give it a new one
- check_remove_expr_info(&c->info, e);
+ check_remove_expr_info(&c->checker->info, e);
if (old.is_lhs && !is_type_integer(type)) {
gbString expr_str = expr_to_string(e);
@@ -2223,17 +2222,17 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
return;
}
- add_type_and_value(&c->info, e, old.mode, type, old.value);
+ add_type_and_value(&c->checker->info, e, old.mode, type, old.value);
}
-void update_expr_value(Checker *c, AstNode *e, ExactValue value) {
- ExprInfo *found = check_get_expr_info(&c->info, e);
+void update_expr_value(CheckerContext *c, AstNode *e, ExactValue value) {
+ ExprInfo *found = check_get_expr_info(&c->checker->info, e);
if (found) {
found->value = value;
}
}
-void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) {
+void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_type) {
gbString expr_str = expr_to_string(operand->expr);
gbString type_str = type_to_string(target_type);
char *extra_text = "";
@@ -2269,7 +2268,7 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
return v;
}
-void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
+void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
GB_ASSERT_NOT_NULL(target_type);
if (operand->mode == Addressing_Invalid ||
operand->mode == Addressing_Type ||
@@ -2464,7 +2463,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
update_expr_type(c, operand->expr, target_type, true);
}
-bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 max_count, i64 *value) {
+bool check_index_value(CheckerContext *c, bool open_range, AstNode *index_value, i64 max_count, i64 *value) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, index_value);
if (operand.mode == Addressing_Invalid) {
@@ -2487,7 +2486,7 @@ bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 ma
}
if (operand.mode == Addressing_Constant &&
- (c->context.stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
+ (c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
i64 i = exact_value_to_integer(operand.value).value_integer;
if (i < 0) {
gbString expr_str = expr_to_string(operand.expr);
@@ -2522,7 +2521,7 @@ bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 ma
return true;
}
-Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) {
+Entity *check_selector(CheckerContext *c, Operand *operand, AstNode *node, Type *type_hint) {
ast_node(se, SelectorExpr, node);
bool check_op_expr = true;
@@ -2550,7 +2549,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
if (op_expr->kind == AstNode_Ident) {
String op_name = op_expr->Ident.token.string;
- Entity *e = scope_lookup_entity(c->context.scope, op_name);
+ Entity *e = scope_lookup_entity(c->scope, op_name);
bool is_alias = false;
while (e != nullptr && e->kind == Entity_Alias) {
@@ -2813,7 +2812,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
return entity;
}
-bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
+bool check_builtin_procedure(CheckerContext *c, Operand *operand, AstNode *call, i32 id) {
GB_ASSERT(call->kind == AstNode_CallExpr);
ast_node(ce, CallExpr, call);
BuiltinProc *bp = &builtin_procs[id];
@@ -3365,7 +3364,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false;
}
// NOTE(bill): Prevent type cycles for procedure declarations
- if (c->context.curr_proc_sig == o.type) {
+ if (c->curr_proc_sig == o.type) {
gbString s = expr_to_string(o.expr);
error(o.expr, "Invalid cyclic type usage from 'type_of', got '%s'", s);
gb_string_free(s);
@@ -3383,12 +3382,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
case BuiltinProc_type_info_of: {
// proc type_info_of(Type) -> ^Type_Info
- if (c->context.scope->is_global) {
+ if (c->scope->is_global) {
compiler_error("'type_info_of' Cannot be declared within a #shared_global_scope due to how the internals of the compiler works");
}
// NOTE(bill): The type information may not be setup yet
- init_preload(c);
+ init_preload(c->checker);
AstNode *expr = ce->args[0];
Operand o = {};
check_expr_or_type(c, &o, expr);
@@ -3418,12 +3417,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
case BuiltinProc_typeid_of: {
// proc typeid_of(Type) -> typeid
- if (c->context.scope->is_global) {
+ if (c->scope->is_global) {
compiler_error("'typeid_of' Cannot be declared within a #shared_global_scope due to how the internals of the compiler works");
}
// NOTE(bill): The type information may not be setup yet
- init_preload(c);
+ init_preload(c->checker);
AstNode *expr = ce->args[0];
Operand o = {};
check_expr_or_type(c, &o, expr);
@@ -4086,13 +4085,13 @@ break;
}
-isize add_dependencies_from_unpacking(Checker *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) {
+isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) {
if (lhs != nullptr) {
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
Entity *e = lhs[tuple_index + j];
- DeclInfo *decl = decl_info_of_entity(&c->info, e);
+ DeclInfo *decl = decl_info_of_entity(&c->checker->info, e);
if (decl != nullptr) {
- c->context.decl = decl; // will be reset by the 'defer' any way
+ c->decl = decl; // will be reset by the 'defer' any way
for_array(k, decl->deps.entries) {
Entity *dep = decl->deps.entries[k].ptr;
add_declaration_dependency(c, dep); // TODO(bill): Should this be here?
@@ -4104,12 +4103,12 @@ isize add_dependencies_from_unpacking(Checker *c, Entity **lhs, isize lhs_count,
}
-void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Array<Operand> *operands, Array<AstNode *> rhs, bool allow_ok, bool *optional_ok_ = nullptr) {
+void check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Operand> *operands, Array<AstNode *> rhs, bool allow_ok, bool *optional_ok_ = nullptr) {
bool optional_ok = false;
isize tuple_index = 0;
for_array(i, rhs) {
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
+ CheckerContext c_ = *ctx;
+ CheckerContext *c = &c_;
Operand o = {};
@@ -4118,8 +4117,8 @@ void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Array<Ope
if (lhs != nullptr && tuple_index < lhs_count) {
// NOTE(bill): override DeclInfo for dependency
Entity *e = lhs[tuple_index];
- DeclInfo *decl = decl_info_of_entity(&c->info, e);
- if (decl) c->context.decl = decl;
+ DeclInfo *decl = decl_info_of_entity(&c->checker->info, e);
+ if (decl) c->decl = decl;
type_hint = e->type;
}
@@ -4134,7 +4133,7 @@ void check_unpack_arguments(Checker *c, Entity **lhs, isize lhs_count, Array<Ope
if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
(o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
Type *tuple = make_optional_ok_type(o.type);
- add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value);
+ add_type_and_value(&c->checker->info, o.expr, o.mode, tuple, o.value);
Operand val = o;
Operand ok = o;
@@ -4547,7 +4546,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
return err;
}
-CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
+CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, AstNode *call) {
ast_node(ce, CallExpr, call);
CallArgumentCheckerType *call_checker = check_call_arguments_internal;
@@ -4595,12 +4594,12 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
if (pt != nullptr && is_type_proc(pt)) {
CallArgumentError err = CallArgumentError_None;
CallArgumentData data = {};
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
- c->context.no_polymorphic_errors = true;
- c->context.allow_polymorphic_types = is_type_polymorphic(pt);
+ CheckerContext ctx = *c;
+
+ ctx.no_polymorphic_errors = true;
+ ctx.allow_polymorphic_types = is_type_polymorphic(pt);
- err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
+ err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
if (err == CallArgumentError_None) {
valids[valid_count].index = i;
@@ -4723,7 +4722,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
ident = s;
}
- Entity *e = entity_of_ident(&c->info, ident);
+ Entity *e = entity_of_ident(&c->checker->info, ident);
CallArgumentData data = {};
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
@@ -4755,7 +4754,7 @@ isize lookup_polymorphic_struct_parameter(TypeStruct *st, String parameter_name)
}
-CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, AstNode *call) {
+CallArgumentError check_polymorphic_struct_type(CheckerContext *c, Operand *operand, AstNode *call) {
ast_node(ce, CallExpr, call);
Type *original_type = operand->type;
@@ -4945,7 +4944,7 @@ CallArgumentError check_polymorphic_struct_type(Checker *c, Operand *operand, As
}
-ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
+ExprKind check_call_expr(CheckerContext *c, Operand *operand, AstNode *call) {
ast_node(ce, CallExpr, call);
if (ce->proc != nullptr &&
ce->proc->kind == AstNode_BasicDirective) {
@@ -4956,7 +4955,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
operand->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc;
operand->type = t_invalid;
- add_type_and_value(&c->info, ce->proc, operand->mode, operand->type, operand->value);
+ add_type_and_value(&c->checker->info, ce->proc, operand->mode, operand->type, operand->value);
} else {
GB_PANIC("Unhandled #%.*s", LIT(name));
}
@@ -5014,7 +5013,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
Type *ot = operand->type; GB_ASSERT(ot->kind == Type_Named);
Entity *e = ot->Named.type_name;
add_entity_use(c, ident, e);
- add_type_and_value(&c->info, call, Addressing_Type, ot, empty_exact_value);
+ add_type_and_value(&c->checker->info, call, Addressing_Type, ot, empty_exact_value);
} else {
operand->mode = Addressing_Invalid;
operand->type = t_invalid;
@@ -5122,7 +5121,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
}
-void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
+void check_expr_with_type_hint(CheckerContext *c, Operand *o, AstNode *e, Type *t) {
check_expr_base(c, o, e, t);
check_not_tuple(c, o);
char *err_str = nullptr;
@@ -5206,7 +5205,7 @@ bool ternary_compare_types(Type *x, Type *y) {
return are_types_identical(x, y);
}
-ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
+ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, AstNode *node, Type *type_hint) {
ExprKind kind = Expr_Stmt;
o->mode = Addressing_Invalid;
@@ -5223,12 +5222,12 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
case_ast_node(i, Implicit, node)
switch (i->kind) {
case Token_context:
- if (c->context.proc_name.len == 0) {
+ if (c->proc_name.len == 0) {
error(node, "'context' is only allowed within procedures");
return kind;
}
- init_preload(c);
+ init_preload(c->checker);
o->mode = Addressing_Immutable;
o->type = t_context;
break;
@@ -5299,16 +5298,16 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
o->type = t_untyped_integer;
o->value = exact_value_i64(bd->token.pos.line);
} else if (bd->name == "procedure") {
- if (c->context.curr_proc_decl == nullptr) {
+ if (c->curr_proc_decl == nullptr) {
error(node, "#procedure may only be used within procedures");
o->type = t_untyped_string;
o->value = exact_value_string(str_lit(""));
} else {
o->type = t_untyped_string;
- o->value = exact_value_string(c->context.proc_name);
+ o->value = exact_value_string(c->proc_name);
}
} else if (bd->name == "caller_location") {
- init_preload(c);
+ init_preload(c->checker);
error(node, "#caller_location may only be used as a default argument parameter");
o->type = t_source_code_location;
o->mode = Addressing_Value;
@@ -5324,26 +5323,27 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
case_end;
case_ast_node(pl, ProcLit, node);
- CheckerContext prev_context = c->context;
+ CheckerContext ctx = *c;
+
DeclInfo *decl = nullptr;
Type *type = alloc_type(Type_Proc);
- check_open_scope(c, pl->type);
+ check_open_scope(&ctx, pl->type);
{
- decl = make_decl_info(c->allocator, c->context.scope, c->context.decl);
+ decl = make_decl_info(ctx.allocator, ctx.scope, ctx.decl);
decl->proc_lit = node;
- c->context.decl = decl;
+ ctx.decl = decl;
if (pl->tags != 0) {
error(node, "A procedure literal cannot have tags");
pl->tags = 0; // TODO(bill): Should I zero this?!
}
- check_procedure_type(c, type, pl->type);
+ check_procedure_type(&ctx, type, pl->type);
if (!is_type_proc(type)) {
gbString str = expr_to_string(node);
error(node, "Invalid procedure literal '%s'", str);
gb_string_free(str);
- check_close_scope(c);
+ check_close_scope(&ctx);
return kind;
}
@@ -5352,11 +5352,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind;
}
- check_procedure_later(c, c->context.file, empty_token, decl, type, pl->body, pl->tags);
+ check_procedure_later(ctx.checker, ctx.file, empty_token, decl, type, pl->body, pl->tags);
}
- check_close_scope(c);
+ check_close_scope(&ctx);
- c->context = prev_context;
o->mode = Addressing_Value;
o->type = type;
@@ -6210,7 +6209,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind;
}
-ExprKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
+ExprKind check_expr_base(CheckerContext *c, Operand *o, AstNode *node, Type *type_hint) {
ExprKind kind = check_expr_base_internal(c, o, node, type_hint);
Type *type = nullptr;
ExactValue value = {ExactValue_Invalid};
@@ -6231,16 +6230,16 @@ ExprKind check_expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint)
}
if (type != nullptr && is_type_untyped(type)) {
- add_untyped(&c->info, node, false, o->mode, type, value);
+ add_untyped(&c->checker->info, node, false, o->mode, type, value);
} else {
- add_type_and_value(&c->info, node, o->mode, type, value);
+ add_type_and_value(&c->checker->info, node, o->mode, type, value);
}
return kind;
}
-void check_multi_expr(Checker *c, Operand *o, AstNode *e) {
+void check_multi_expr(CheckerContext *c, Operand *o, AstNode *e) {
check_expr_base(c, o, e, nullptr);
switch (o->mode) {
default:
@@ -6255,7 +6254,7 @@ void check_multi_expr(Checker *c, Operand *o, AstNode *e) {
o->mode = Addressing_Invalid;
}
-void check_not_tuple(Checker *c, Operand *o) {
+void check_not_tuple(CheckerContext *c, Operand *o) {
if (o->mode == Addressing_Value) {
// NOTE(bill): Tuples are not first class thus never named
if (o->type->kind == Type_Tuple) {
@@ -6268,13 +6267,13 @@ void check_not_tuple(Checker *c, Operand *o) {
}
}
-void check_expr(Checker *c, Operand *o, AstNode *e) {
+void check_expr(CheckerContext *c, Operand *o, AstNode *e) {
check_multi_expr(c, o, e);
check_not_tuple(c, o);
}
-void check_expr_or_type(Checker *c, Operand *o, AstNode *e, Type *type_hint) {
+void check_expr_or_type(CheckerContext *c, Operand *o, AstNode *e, Type *type_hint) {
check_expr_base(c, o, e, type_hint);
check_not_tuple(c, o);
error_operand_no_value(o);
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 8ec5ac9f4..8e6406cc4 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -1,10 +1,10 @@
-void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
+void check_stmt_list(CheckerContext *ctx, Array<AstNode *> stmts, u32 flags) {
if (stmts.count == 0) {
return;
}
if (flags&Stmt_CheckScopeDecls) {
- check_scope_decls(c, stmts, cast(isize)(1.2*stmts.count));
+ check_scope_decls(ctx, stmts, cast(isize)(1.2*stmts.count));
}
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
@@ -39,7 +39,7 @@ void check_stmt_list(Checker *c, Array<AstNode *> stmts, u32 flags) {
}
}
- check_stmt(c, n, new_flags);
+ check_stmt(ctx, n, new_flags);
}
}
@@ -176,7 +176,7 @@ bool check_is_terminating(AstNode *node) {
return false;
}
-Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
+Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
if (rhs->mode == Addressing_Invalid) {
return nullptr;
}
@@ -190,7 +190,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
// NOTE(bill): Ignore assignments to '_'
if (is_blank_ident(node)) {
- check_assignment(c, rhs, nullptr, str_lit("assignment to '_' identifier"));
+ check_assignment(ctx, rhs, nullptr, str_lit("assignment to '_' identifier"));
if (rhs->mode == Addressing_Invalid) {
return nullptr;
}
@@ -208,7 +208,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
}
if (rhs->mode == Addressing_ProcGroup) {
- Array<Entity *> procs = proc_group_entities(c, *rhs);
+ Array<Entity *> procs = proc_group_entities(ctx, *rhs);
GB_ASSERT(procs.count > 0);
// NOTE(bill): These should be done
@@ -220,9 +220,9 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
Operand x = {};
x.mode = Addressing_Value;
x.type = t;
- if (check_is_assignable_to(c, &x, lhs->type)) {
+ if (check_is_assignable_to(ctx, &x, lhs->type)) {
e = procs[i];
- add_entity_use(c, rhs->expr, e);
+ add_entity_use(ctx, rhs->expr, e);
break;
}
}
@@ -236,7 +236,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
} else {
if (node->kind == AstNode_Ident) {
ast_node(i, Ident, node);
- e = scope_lookup_entity(c->context.scope, i->token.string);
+ e = scope_lookup_entity(ctx->scope, i->token.string);
if (e != nullptr && e->kind == Entity_Variable) {
used = (e->flags & EntityFlag_Used) != 0; // TODO(bill): Make backup just in case
}
@@ -292,7 +292,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
AstNode *ln = unparen_expr(lhs->expr);
if (ln->kind == AstNode_IndexExpr) {
AstNode *x = ln->IndexExpr.expr;
- TypeAndValue tav = type_and_value_of_expr(&c->info, x);
+ TypeAndValue tav = type_and_value_of_expr(&ctx->checker->info, x);
GB_ASSERT(tav.mode != Addressing_Invalid);
if (tav.mode != Addressing_Variable) {
if (!is_type_pointer(tav.type)) {
@@ -312,7 +312,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
// NOTE(bill): Extra error checks
Operand op_c = {Addressing_Invalid};
ast_node(se, SelectorExpr, lhs->expr);
- check_expr(c, &op_c, se->expr);
+ check_expr(ctx, &op_c, se->expr);
if (op_c.mode == Addressing_MapIndex) {
gbString str = expr_to_string(lhs->expr);
error(lhs->expr, "Cannot assign to struct field '%s' in map", str);
@@ -333,7 +333,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
}
}
- check_assignment(c, rhs, assignment_type, str_lit("assignment"));
+ check_assignment(ctx, rhs, assignment_type, str_lit("assignment"));
if (rhs->mode == Addressing_Invalid) {
return nullptr;
}
@@ -342,13 +342,13 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) {
}
-void check_stmt_internal(Checker *c, AstNode *node, u32 flags);
-void check_stmt(Checker *c, AstNode *node, u32 flags) {
- u32 prev_stmt_state_flags = c->context.stmt_state_flags;
+void check_stmt_internal(CheckerContext *ctx, AstNode *node, u32 flags);
+void check_stmt(CheckerContext *ctx, AstNode *node, u32 flags) {
+ u32 prev_stmt_state_flags = ctx->stmt_state_flags;
if (node->stmt_state_flags != 0) {
u32 in = node->stmt_state_flags;
- u32 out = c->context.stmt_state_flags;
+ u32 out = ctx->stmt_state_flags;
if (in & StmtStateFlag_no_bounds_check) {
out |= StmtStateFlag_no_bounds_check;
@@ -359,18 +359,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
out &= ~StmtStateFlag_no_bounds_check;
}
- c->context.stmt_state_flags = out;
+ ctx->stmt_state_flags = out;
}
- check_stmt_internal(c, node, flags);
+ check_stmt_internal(ctx, node, flags);
- c->context.stmt_state_flags = prev_stmt_state_flags;
+ ctx->stmt_state_flags = prev_stmt_state_flags;
}
-void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
+void check_when_stmt(CheckerContext *ctx, AstNodeWhenStmt *ws, u32 flags) {
Operand operand = {Addressing_Invalid};
- check_expr(c, &operand, ws->cond);
+ check_expr(ctx, &operand, ws->cond);
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
error(ws->cond, "Non-constant boolean 'when' condition");
return;
@@ -381,14 +381,14 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
}
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool) {
- check_stmt_list(c, ws->body->BlockStmt.stmts, flags);
+ check_stmt_list(ctx, ws->body->BlockStmt.stmts, flags);
} else if (ws->else_stmt) {
switch (ws->else_stmt->kind) {
case AstNode_BlockStmt:
- check_stmt_list(c, ws->else_stmt->BlockStmt.stmts, flags);
+ check_stmt_list(ctx, ws->else_stmt->BlockStmt.stmts, flags);
break;
case AstNode_WhenStmt:
- check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
+ check_when_stmt(ctx, &ws->else_stmt->WhenStmt, flags);
break;
default:
error(ws->else_stmt, "Invalid 'else' statement in 'when' statement");
@@ -397,7 +397,7 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
}
}
-void check_label(Checker *c, AstNode *label) {
+void check_label(CheckerContext *ctx, AstNode *label) {
if (label == nullptr) {
return;
}
@@ -413,15 +413,15 @@ void check_label(Checker *c, AstNode *label) {
}
- if (c->context.curr_proc_decl == nullptr) {
+ if (ctx->curr_proc_decl == nullptr) {
error(l->name, "A label is only allowed within a procedure");
return;
}
- GB_ASSERT(c->context.decl != nullptr);
+ GB_ASSERT(ctx->decl != nullptr);
bool ok = true;
- for_array(i, c->context.decl->labels) {
- BlockLabel bl = c->context.decl->labels[i];
+ for_array(i, ctx->decl->labels) {
+ BlockLabel bl = ctx->decl->labels[i];
if (bl.name == name) {
error(label, "Duplicate label with the name '%.*s'", LIT(name));
ok = false;
@@ -429,24 +429,24 @@ void check_label(Checker *c, AstNode *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;
+ Entity *e = alloc_entity_label(ctx->scope, l->name->Ident.token, t_invalid, label);
+ add_entity(ctx->checker, ctx->scope, l->name, e);
+ e->parent_proc_decl = ctx->curr_proc_decl;
if (ok) {
BlockLabel bl = {name, label};
- array_add(&c->context.decl->labels, bl);
+ array_add(&ctx->decl->labels, bl);
}
}
// Returns 'true' for 'continue', 'false' for 'return'
-bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) {
+bool check_using_stmt_entity(CheckerContext *ctx, AstNodeUsingStmt *us, AstNode *expr, bool is_selector, Entity *e) {
if (e == nullptr) {
error(us->token, "'using' applied to an unknown entity");
return true;
}
- add_entity_use(c, expr, e);
+ add_entity_use(ctx, expr, e);
switch (e->kind) {
case Entity_TypeName: {
@@ -456,7 +456,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
Entity *f = t->Enum.fields[i];
if (!is_entity_exported(f)) continue;
- Entity *found = scope_insert_entity(c->context.scope, f);
+ Entity *found = scope_insert_entity(ctx->scope, f);
if (found != nullptr) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while 'using' '%s' of: %.*s", expr_str, LIT(found->token.string));
@@ -478,7 +478,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
Entity *decl = scope->elements.entries[i].value;
if (!is_entity_exported(decl)) continue;
- Entity *found = scope_insert_entity(c->context.scope, decl);
+ Entity *found = scope_insert_entity(ctx->scope, decl);
if (found != nullptr) {
gbString expr_str = expr_to_string(expr);
error(us->token,
@@ -501,13 +501,13 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
// TODO(bill): Make it work for unions too
- Scope *found = scope_of_node(&c->info, t->Struct.node);
+ Scope *found = scope_of_node(&ctx->checker->info, t->Struct.node);
for_array(i, found->elements.entries) {
Entity *f = found->elements.entries[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
uvar->using_expr = expr;
- Entity *prev = scope_insert_entity(c->context.scope, uvar);
+ Entity *prev = scope_insert_entity(ctx->scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
error(us->token, "Namespace collision while using '%s' of: '%.*s'", expr_str, LIT(prev->token.string));
@@ -559,7 +559,7 @@ struct TypeAndToken {
Token token;
};
-void add_constant_switch_case(Checker *c, Map<TypeAndToken> *seen, Operand operand, bool use_expr = true) {
+void add_constant_switch_case(CheckerContext *ctx, Map<TypeAndToken> *seen, Operand operand, bool use_expr = true) {
if (operand.mode != Addressing_Constant) {
return;
}
@@ -570,8 +570,8 @@ void add_constant_switch_case(Checker *c, Map<TypeAndToken> *seen, Operand opera
TypeAndToken *found = map_get(seen, key);
if (found != nullptr) {
isize count = multi_map_count(seen, key);
- TypeAndToken *taps = gb_alloc_array(c->allocator, TypeAndToken, count);
- defer (gb_free(c->allocator, taps));
+ TypeAndToken *taps = gb_alloc_array(ctx->allocator, TypeAndToken, count);
+ defer (gb_free(ctx->allocator, taps));
multi_map_get_all(seen, key, taps);
for (isize i = 0; i < count; i++) {
@@ -600,23 +600,23 @@ void add_constant_switch_case(Checker *c, Map<TypeAndToken> *seen, Operand opera
multi_map_insert(seen, key, tap);
}
-void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
+void check_switch_stmt(CheckerContext *ctx, 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_open_scope(ctx, node);
+ defer (check_close_scope(ctx));
- check_label(c, ss->label); // TODO(bill): What should the label's "scope" be?
+ check_label(ctx, ss->label); // TODO(bill): What should the label's "scope" be?
if (ss->init != nullptr) {
- check_stmt(c, ss->init, 0);
+ check_stmt(ctx, ss->init, 0);
}
if (ss->tag != nullptr) {
- check_expr(c, &x, ss->tag);
- check_assignment(c, &x, nullptr, str_lit("switch expression"));
+ check_expr(ctx, &x, ss->tag);
+ check_assignment(ctx, &x, nullptr, str_lit("switch expression"));
} else {
x.mode = Addressing_Constant;
x.type = t_bool;
@@ -626,7 +626,7 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
token.pos = ast_node_token(ss->body).pos;
token.string = str_lit("true");
- x.expr = gb_alloc_item(c->allocator, AstNode);
+ x.expr = gb_alloc_item(ctx->allocator, AstNode);
x.expr->kind = AstNode_Ident;
x.expr->Ident.token = token;
}
@@ -687,14 +687,14 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
ast_node(ie, BinaryExpr, expr);
Operand lhs = {};
Operand rhs = {};
- check_expr(c, &lhs, ie->left);
+ check_expr(ctx, &lhs, ie->left);
if (x.mode == Addressing_Invalid) {
continue;
}
if (lhs.mode == Addressing_Invalid) {
continue;
}
- check_expr(c, &rhs, ie->right);
+ check_expr(ctx, &rhs, ie->right);
if (rhs.mode == Addressing_Invalid) {
continue;
}
@@ -711,7 +711,7 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
Operand a = lhs;
Operand b = rhs;
- check_comparison(c, &a, &x, Token_LtEq);
+ check_comparison(ctx, &a, &x, Token_LtEq);
if (a.mode == Addressing_Invalid) {
continue;
}
@@ -721,7 +721,7 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
default: error(ie->op, "Invalid interval operator"); continue;
}
- check_comparison(c, &b, &x, op);
+ check_comparison(ctx, &b, &x, op);
if (b.mode == Addressing_Invalid) {
continue;
}
@@ -736,32 +736,32 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
Operand a1 = lhs;
Operand b1 = rhs;
- check_comparison(c, &a1, &b1, op);
+ check_comparison(ctx, &a1, &b1, op);
if (complete) {
error(lhs.expr, "#complete switch statement does not allow ranges");
}
- add_constant_switch_case(c, &seen, lhs);
+ add_constant_switch_case(ctx, &seen, lhs);
if (op == Token_LtEq) {
- add_constant_switch_case(c, &seen, rhs);
+ add_constant_switch_case(ctx, &seen, rhs);
}
} else {
Operand y = {};
- check_expr(c, &y, expr);
+ check_expr(ctx, &y, expr);
if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) {
continue;
}
- convert_to_typed(c, &y, x.type);
+ convert_to_typed(ctx, &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);
+ check_comparison(ctx, &z, &x, Token_CmpEq);
if (z.mode == Addressing_Invalid) {
continue;
}
@@ -772,13 +772,13 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
continue;
}
- add_constant_switch_case(c, &seen, y);
+ add_constant_switch_case(ctx, &seen, y);
}
}
- check_open_scope(c, stmt);
- check_stmt_list(c, cc->stmts, mod_flags);
- check_close_scope(c);
+ check_open_scope(ctx, stmt);
+ check_stmt_list(ctx, cc->stmts, mod_flags);
+ check_close_scope(ctx);
}
if (complete) {
@@ -786,7 +786,7 @@ void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
GB_ASSERT(is_type_enum(et));
auto fields = et->Enum.fields;
- auto unhandled = array_make<Entity *>(c->allocator, 0, fields.count);
+ auto unhandled = array_make<Entity *>(ctx->allocator, 0, fields.count);
defer (array_free(&unhandled));
for_array(i, fields) {
@@ -838,15 +838,15 @@ TypeSwitchKind check_valid_type_switch_type(Type *type) {
return TypeSwitch_Invalid;
}
-void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
+void check_type_switch_stmt(CheckerContext *ctx, AstNode *node, u32 mod_flags) {
ast_node(ss, TypeSwitchStmt, node);
Operand x = {};
mod_flags |= Stmt_BreakAllowed;
- check_open_scope(c, node);
- defer (check_close_scope(c));
+ check_open_scope(ctx, node);
+ defer (check_close_scope(ctx));
- check_label(c, ss->label); // TODO(bill): What should the label's "scope" be?
+ check_label(ctx, ss->label); // TODO(bill): What should the label's "scope" be?
if (ss->tag->kind != AstNode_AssignStmt) {
error(ss->tag, "Expected an 'in' assignment for this type switch statement");
@@ -866,9 +866,9 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
AstNode *lhs = as->lhs[0];
AstNode *rhs = as->rhs[0];
- check_expr(c, &x, rhs);
- check_assignment(c, &x, nullptr, str_lit("type switch expression"));
- add_type_info_type(c, x.type);
+ check_expr(ctx, &x, rhs);
+ check_assignment(ctx, &x, nullptr, str_lit("type switch expression"));
+ add_type_info_type(ctx, x.type);
TypeSwitchKind switch_kind = check_valid_type_switch_type(x.type);
if (switch_kind == TypeSwitch_Invalid) {
@@ -941,7 +941,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
AstNode *type_expr = cc->list[type_index];
if (type_expr != nullptr) { // Otherwise it's a default expression
Operand y = {};
- check_expr_or_type(c, &y, type_expr);
+ check_expr_or_type(ctx, &y, type_expr);
if (switch_kind == TypeSwitch_Union) {
GB_ASSERT(is_type_union(bt));
@@ -960,10 +960,10 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
continue;
}
case_type = y.type;
- add_type_info_type(c, y.type);
+ add_type_info_type(ctx, y.type);
} else if (switch_kind == TypeSwitch_Any) {
case_type = y.type;
- add_type_info_type(c, y.type);
+ add_type_info_type(ctx, y.type);
} else {
GB_PANIC("Unknown type to type switch statement");
}
@@ -996,19 +996,19 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
if (case_type == nullptr) {
case_type = x.type;
}
- add_type_info_type(c, case_type);
+ add_type_info_type(ctx, case_type);
- check_open_scope(c, stmt);
+ check_open_scope(ctx, stmt);
{
- Entity *tag_var = alloc_entity_variable(c->context.scope, lhs->Ident.token, case_type, false, EntityState_Resolved);
+ Entity *tag_var = alloc_entity_variable(ctx->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);
- add_entity_use(c, lhs, tag_var);
- add_implicit_entity(c, stmt, tag_var);
+ add_entity(ctx->checker, ctx->scope, lhs, tag_var);
+ add_entity_use(ctx, lhs, tag_var);
+ add_implicit_entity(ctx, stmt, tag_var);
}
- check_stmt_list(c, cc->stmts, mod_flags);
- check_close_scope(c);
+ check_stmt_list(ctx, cc->stmts, mod_flags);
+ check_close_scope(ctx);
}
if (complete) {
@@ -1016,7 +1016,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
GB_ASSERT(is_type_union(ut));
auto variants = ut->Union.variants;
- auto unhandled = array_make<Type *>(c->allocator, 0, variants.count);
+ auto unhandled = array_make<Type *>(ctx->allocator, 0, variants.count);
defer (array_free(&unhandled));
for_array(i, variants) {
@@ -1046,7 +1046,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
}
}
-void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
+void check_stmt_internal(CheckerContext *ctx, AstNode *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
case_ast_node(_, EmptyStmt, node); case_end;
@@ -1055,7 +1055,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(es, ExprStmt, node)
Operand operand = {Addressing_Invalid};
- ExprKind kind = check_expr_base(c, &operand, es->expr, nullptr);
+ ExprKind kind = check_expr_base(ctx, &operand, es->expr, nullptr);
switch (operand.mode) {
case Addressing_Type: {
gbString str = type_to_string(operand.type);
@@ -1072,7 +1072,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
if (operand.expr->kind == AstNode_CallExpr) {
AstNodeCallExpr *ce = &operand.expr->CallExpr;
- Type *t = type_of_expr(&c->info, ce->proc);
+ Type *t = type_of_expr(&ctx->checker->info, ce->proc);
if (is_type_proc(t)) {
if (t->Proc.require_results) {
gbString expr_str = expr_to_string(ce->proc);
@@ -1094,7 +1094,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(ts, TagStmt, node);
// TODO(bill): Tag Statements
error(node, "Tag statements are not supported yet");
- check_stmt(c, ts->stmt, flags);
+ check_stmt(ctx, ts->stmt, flags);
case_end;
case_ast_node(as, AssignStmt, node);
@@ -1110,8 +1110,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
- auto lhs_operands = array_make<Operand>(c->allocator, lhs_count);
- auto rhs_operands = array_make<Operand>(c->allocator, 0, 2*lhs_count);
+ auto lhs_operands = array_make<Operand>(ctx->allocator, lhs_count);
+ auto rhs_operands = array_make<Operand>(ctx->allocator, 0, 2*lhs_count);
defer (array_free(&lhs_operands));
defer (array_free(&rhs_operands));
@@ -1121,11 +1121,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
o->expr = as->lhs[i];
o->mode = Addressing_Value;
} else {
- check_expr(c, &lhs_operands[i], as->lhs[i]);
+ check_expr(ctx, &lhs_operands[i], as->lhs[i]);
}
}
- check_unpack_arguments(c, nullptr, lhs_operands.count, &rhs_operands, as->rhs, true);
+ check_unpack_arguments(ctx, nullptr, lhs_operands.count, &rhs_operands, as->rhs, true);
isize rhs_count = rhs_operands.count;
for_array(i, rhs_operands) {
@@ -1136,7 +1136,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
- check_assignment_variable(c, &lhs_operands[i], &rhs_operands[i]);
+ check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]);
}
if (lhs_count != rhs_count) {
error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
@@ -1165,13 +1165,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
be->left = as->lhs[0];
be->right = as->rhs[0];
- check_expr(c, &lhs, as->lhs[0]);
- check_binary_expr(c, &rhs, &binary_expr);
+ check_expr(ctx, &lhs, as->lhs[0]);
+ check_binary_expr(ctx, &rhs, &binary_expr);
if (rhs.mode == Addressing_Invalid) {
return;
}
// NOTE(bill): Only use the first one will be used
- check_assignment_variable(c, &lhs, &rhs);
+ check_assignment_variable(ctx, &lhs, &rhs);
break;
}
@@ -1179,31 +1179,31 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_end;
case_ast_node(bs, BlockStmt, node);
- check_open_scope(c, node);
- check_stmt_list(c, bs->stmts, flags);
- check_close_scope(c);
+ check_open_scope(ctx, node);
+ check_stmt_list(ctx, bs->stmts, flags);
+ check_close_scope(ctx);
case_end;
case_ast_node(is, IfStmt, node);
- check_open_scope(c, node);
+ check_open_scope(ctx, node);
if (is->init != nullptr) {
- check_stmt(c, is->init, 0);
+ check_stmt(ctx, is->init, 0);
}
Operand operand = {Addressing_Invalid};
- check_expr(c, &operand, is->cond);
+ check_expr(ctx, &operand, is->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error(is->cond, "Non-boolean condition in 'if' statement");
}
- check_stmt(c, is->body, mod_flags);
+ check_stmt(ctx, is->body, mod_flags);
if (is->else_stmt != nullptr) {
switch (is->else_stmt->kind) {
case AstNode_IfStmt:
case AstNode_BlockStmt:
- check_stmt(c, is->else_stmt, mod_flags);
+ check_stmt(ctx, is->else_stmt, mod_flags);
break;
default:
error(is->else_stmt, "Invalid 'else' statement in 'if' statement");
@@ -1211,22 +1211,22 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
}
- check_close_scope(c);
+ check_close_scope(ctx);
case_end;
case_ast_node(ws, WhenStmt, node);
- check_when_stmt(c, ws, flags);
+ check_when_stmt(ctx, ws, flags);
case_end;
case_ast_node(rs, ReturnStmt, node);
- GB_ASSERT(c->context.curr_proc_sig != nullptr);
+ GB_ASSERT(ctx->curr_proc_sig != nullptr);
- if (c->context.in_defer) {
+ if (ctx->in_defer) {
error(rs->token, "You cannot 'return' within a defer statement");
break;
}
- Type *proc_type = c->context.curr_proc_sig;
+ Type *proc_type = ctx->curr_proc_sig;
GB_ASSERT(proc_type != nullptr);
GB_ASSERT(proc_type->kind == Type_Proc);
// Type *proc_type = c->proc_stack[c->proc_stack.count-1];
@@ -1241,7 +1241,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
defer (array_free(&operands));
- check_unpack_arguments(c, nullptr, -1, &operands, rs->results, false);
+ check_unpack_arguments(ctx, nullptr, -1, &operands, rs->results, false);
if (result_count == 0 && rs->results.count > 0) {
error(rs->results[0], "No return values expected");
@@ -1253,7 +1253,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
isize max_count = rs->results.count;
for (isize i = 0; i < max_count; i++) {
Entity *e = pt->results->Tuple.variables[i];
- check_assignment(c, &operands[i], e->type, str_lit("return statement"));
+ check_assignment(ctx, &operands[i], e->type, str_lit("return statement"));
}
}
case_end;
@@ -1261,37 +1261,37 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(fs, ForStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
- check_open_scope(c, node);
- check_label(c, fs->label); // TODO(bill): What should the label's "scope" be?
+ check_open_scope(ctx, node);
+ check_label(ctx, fs->label); // TODO(bill): What should the label's "scope" be?
if (fs->init != nullptr) {
- check_stmt(c, fs->init, 0);
+ check_stmt(ctx, fs->init, 0);
}
if (fs->cond != nullptr) {
Operand o = {Addressing_Invalid};
- check_expr(c, &o, fs->cond);
+ check_expr(ctx, &o, fs->cond);
if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
error(fs->cond, "Non-boolean condition in 'for' statement");
}
}
if (fs->post != nullptr) {
- check_stmt(c, fs->post, 0);
+ check_stmt(ctx, fs->post, 0);
if (fs->post->kind != AstNode_AssignStmt &&
fs->post->kind != AstNode_IncDecStmt) {
error(fs->post, "'for' statement post statement must be a simple statement");
}
}
- check_stmt(c, fs->body, new_flags);
+ check_stmt(ctx, fs->body, new_flags);
- check_close_scope(c);
+ check_close_scope(ctx);
case_end;
case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
- check_open_scope(c, node);
- check_label(c, rs->label);
+ check_open_scope(ctx, node);
+ check_label(ctx, rs->label);
Type *val0 = nullptr;
Type *val1 = nullptr;
@@ -1307,29 +1307,29 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid};
- check_expr(c, &x, ie->left);
+ check_expr(ctx, &x, ie->left);
if (x.mode == Addressing_Invalid) {
goto skip_expr;
}
- check_expr(c, &y, ie->right);
+ check_expr(ctx, &y, ie->right);
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
- convert_to_typed(c, &x, y.type);
+ convert_to_typed(ctx, &x, y.type);
if (x.mode == Addressing_Invalid) {
goto skip_expr;
}
- convert_to_typed(c, &y, x.type);
+ convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
- convert_to_typed(c, &x, default_type(y.type));
+ convert_to_typed(ctx, &x, default_type(y.type));
if (x.mode == Addressing_Invalid) {
goto skip_expr;
}
- convert_to_typed(c, &y, default_type(x.type));
+ convert_to_typed(ctx, &y, default_type(x.type));
if (y.mode == Addressing_Invalid) {
goto skip_expr;
}
@@ -1383,13 +1383,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
- add_type_and_value(&c->info, ie->left, x.mode, x.type, x.value);
- add_type_and_value(&c->info, ie->right, y.mode, y.type, y.value);
+ add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value);
+ add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value);
val0 = type;
val1 = t_int;
} else {
Operand operand = {Addressing_Invalid};
- check_expr_or_type(c, &operand, rs->expr);
+ check_expr_or_type(ctx, &operand, rs->expr);
if (operand.mode == Addressing_Type) {
if (!is_type_enum(operand.type)) {
@@ -1400,7 +1400,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} else {
val0 = operand.type;
val1 = t_int;
- add_type_info_type(c, operand.type);
+ add_type_info_type(ctx, operand.type);
goto skip_expr;
}
} else if (operand.mode != Addressing_Invalid) {
@@ -1411,7 +1411,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_type_string(t)) {
val0 = t_rune;
val1 = t_int;
- add_package_dependency(c, "runtime", "__string_decode_rune");
+ add_package_dependency(ctx, "runtime", "__string_decode_rune");
}
break;
case Type_Array:
@@ -1464,12 +1464,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Entity *found = nullptr;
if (!is_blank_ident(str)) {
- found = current_scope_lookup_entity(c->context.scope, str);
+ found = current_scope_lookup_entity(ctx->scope, str);
}
if (found == nullptr) {
bool is_immutable = true;
- entity = alloc_entity_variable(c->context.scope, token, type, is_immutable, EntityState_Resolved);
- add_entity_definition(&c->info, name, entity);
+ entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved);
+ add_entity_definition(&ctx->checker->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
@@ -1495,20 +1495,20 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
for (isize i = 0; i < entity_count; i++) {
- add_entity(c, c->context.scope, entities[i]->identifier, entities[i]);
+ add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]);
}
- check_stmt(c, rs->body, new_flags);
+ check_stmt(ctx, rs->body, new_flags);
- check_close_scope(c);
+ check_close_scope(ctx);
case_end;
case_ast_node(ss, SwitchStmt, node);
- check_switch_stmt(c, node, mod_flags);
+ check_switch_stmt(ctx, node, mod_flags);
case_end;
case_ast_node(ss, TypeSwitchStmt, node);
- check_type_switch_stmt(c, node, mod_flags);
+ check_type_switch_stmt(ctx, node, mod_flags);
case_end;
@@ -1516,10 +1516,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_ast_node_decl(ds->stmt)) {
error(ds->token, "You cannot defer a declaration");
} else {
- bool out_in_defer = c->context.in_defer;
- c->context.in_defer = true;
- check_stmt(c, ds->stmt, 0);
- c->context.in_defer = out_in_defer;
+ bool out_in_defer = ctx->in_defer;
+ ctx->in_defer = true;
+ check_stmt(ctx, ds->stmt, 0);
+ ctx->in_defer = out_in_defer;
}
case_end;
@@ -1554,12 +1554,12 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
AstNode *ident = bs->label;
String name = ident->Ident.token.string;
Operand o = {};
- Entity *e = check_ident(c, &o, ident, nullptr, nullptr, false);
+ Entity *e = check_ident(ctx, &o, ident, nullptr, nullptr, false);
if (e == nullptr) {
error(ident, "Undeclared label name: %.*s", LIT(name));
return;
}
- add_entity_use(c, ident, e);
+ add_entity_use(ctx, ident, e);
if (e->kind != Entity_Label) {
error(ident, "'%.*s' is not a label", LIT(name));
return;
@@ -1581,10 +1581,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand o = {};
switch (expr->kind) {
case AstNode_Ident:
- e = check_ident(c, &o, expr, nullptr, nullptr, true);
+ e = check_ident(ctx, &o, expr, nullptr, nullptr, true);
break;
case AstNode_SelectorExpr:
- e = check_selector(c, &o, expr, nullptr);
+ e = check_selector(ctx, &o, expr, nullptr);
is_selector = true;
break;
case AstNode_Implicit:
@@ -1595,7 +1595,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
continue;
}
- if (!check_using_stmt_entity(c, us, expr, is_selector, e)) {
+ if (!check_using_stmt_entity(ctx, us, expr, is_selector, e)) {
return;
}
}
@@ -1610,15 +1610,15 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Entity *e = nullptr;
Operand o = {};
if (expr->kind == AstNode_Ident) {
- e = check_ident(c, &o, expr, nullptr, nullptr, true);
+ e = check_ident(ctx, &o, expr, nullptr, nullptr, true);
} else if (expr->kind == AstNode_SelectorExpr) {
- e = check_selector(c, &o, expr, nullptr);
+ e = check_selector(ctx, &o, expr, nullptr);
}
if (e == nullptr) {
error(expr, "'using' applied to an unknown entity");
return;
}
- add_entity_use(c, expr, e);
+ add_entity_use(ctx, expr, e);
switch (e->kind) {
@@ -1641,8 +1641,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
continue;
}
- add_entity_use(c, node, f);
- add_entity(c, c->context.scope, node, f);
+ add_entity_use(ctx, node, f);
+ add_entity(ctx->checker, ctx->scope, node, f);
}
} else {
error(node, "'using' can be only applied to enum type entities");
@@ -1670,8 +1670,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
bool implicit_is_found = ptr_set_exists(&scope->implicit, f);
if (is_entity_exported(f) && !implicit_is_found) {
- add_entity_use(c, node, f);
- add_entity(c, c->context.scope, node, f);
+ add_entity_use(ctx, node, f);
+ add_entity(ctx->checker, ctx->scope, node, f);
} else {
error(node, "'%.*s' is exported from '%.*s'", LIT(f->token.string), LIT(e->token.string));
continue;
@@ -1685,7 +1685,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Type *t = base_type(type_deref(e->type));
if (t->kind == Type_Struct) {
// TODO(bill): Make it work for unions too
- Scope *found = scope_of_node(&c->info, t->Struct.node);
+ Scope *found = scope_of_node(&ctx->checker->info, t->Struct.node);
for_array(list_index, uis->list) {
AstNode *node = uis->list[list_index];
ast_node(ident, Ident, node);
@@ -1703,7 +1703,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
uvar->using_expr = expr;
- Entity *prev = scope_insert_entity(c->context.scope, uvar);
+ Entity *prev = scope_insert_entity(ctx->scope, uvar);
if (prev != nullptr) {
gbString expr_str = expr_to_string(expr);
error(node, "Namespace collision while using '%s' of: '%.*s'", expr_str, LIT(prev->token.string));
@@ -1750,36 +1750,34 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(pa, PushContext, node);
Operand op = {};
- check_expr(c, &op, pa->expr);
- check_assignment(c, &op, t_context, str_lit("argument to context <-"));
- check_stmt(c, pa->body, mod_flags);
+ check_expr(ctx, &op, pa->expr);
+ check_assignment(ctx, &op, t_context, str_lit("argument to context <-"));
+ check_stmt(ctx, pa->body, mod_flags);
case_end;
case_ast_node(fb, ForeignBlockDecl, node);
AstNode *foreign_library = fb->foreign_library;
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
-
+ CheckerContext c = *ctx;
if (foreign_library->kind != AstNode_Ident) {
error(foreign_library, "foreign library name must be an identifier");
} else {
- c->context.foreign_context.curr_library = foreign_library;
- c->context.foreign_context.default_cc = ProcCC_CDecl;
+ c.foreign_context.curr_library = foreign_library;
+ c.foreign_context.default_cc = ProcCC_CDecl;
}
- check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr);
+ check_decl_attributes(&c, fb->attributes, foreign_block_decl_attribute, nullptr);
for_array(i, fb->decls) {
AstNode *decl = fb->decls[i];
if (decl->kind == AstNode_ValueDecl && decl->ValueDecl.is_mutable) {
- check_stmt(c, decl, flags);
+ check_stmt(&c, decl, flags);
}
}
case_end;
case_ast_node(vd, ValueDecl, node);
if (vd->is_mutable) {
- Entity **entities = gb_alloc_array(c->allocator, Entity *, vd->names.count);
+ Entity **entities = gb_alloc_array(ctx->allocator, Entity *, vd->names.count);
isize entity_count = 0;
isize new_name_count = 0;
@@ -1794,14 +1792,14 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Entity *found = nullptr;
// NOTE(bill): Ignore assignments to '_'
if (!is_blank_ident(str)) {
- found = current_scope_lookup_entity(c->context.scope, str);
+ found = current_scope_lookup_entity(ctx->scope, str);
new_name_count += 1;
}
if (found == nullptr) {
- entity = alloc_entity_variable(c->context.scope, token, nullptr, false);
+ entity = alloc_entity_variable(ctx->scope, token, nullptr, false);
entity->identifier = name;
- AstNode *fl = c->context.foreign_context.curr_library;
+ AstNode *fl = ctx->foreign_context.curr_library;
if (fl != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident);
entity->Variable.is_foreign = true;
@@ -1819,7 +1817,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (entity == nullptr) {
entity = alloc_entity_dummy_variable(universal_scope, ast_node_token(name));
}
- entity->parent_proc_decl = c->context.curr_proc_decl;
+ entity->parent_proc_decl = ctx->curr_proc_decl;
entities[entity_count++] = entity;
}
@@ -1829,7 +1827,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);
+ init_type = check_type(ctx, vd->type);
if (init_type == nullptr) {
init_type = t_invalid;
} else if (is_type_polymorphic(base_type(init_type))) {
@@ -1847,8 +1845,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// TODO NOTE(bill): This technically checks things multple times
- AttributeContext ac = make_attribute_context(c->context.foreign_context.link_prefix);
- check_decl_attributes(c, vd->attributes, var_decl_attribute, &ac);
+ AttributeContext ac = make_attribute_context(ctx->foreign_context.link_prefix);
+ check_decl_attributes(ctx, vd->attributes, var_decl_attribute, &ac);
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
@@ -1864,7 +1862,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
e->type = init_type;
e->state = EntityState_Resolved;
}
- ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
+ ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
e->Variable.thread_local_model = ac.thread_local_model;
if (ac.link_name.len > 0) {
@@ -1872,8 +1870,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
}
- check_arity_match(c, vd);
- check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
+ check_arity_match(ctx, vd);
+ check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration"));
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
@@ -1890,9 +1888,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (vd->values.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value");
}
- init_entity_foreign_library(c, e);
+ init_entity_foreign_library(ctx, e);
- auto *fp = &c->info.foreigns;
+ auto *fp = &ctx->checker->info.foreigns;
HashKey key = hash_string(name);
Entity **found = map_get(fp, key);
if (found) {
@@ -1910,7 +1908,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
map_set(fp, key, e);
}
}
- add_entity(c, c->context.scope, e->identifier, e);
+ add_entity(ctx->checker, ctx->scope, e->identifier, e);
}
if (vd->is_using != 0) {
@@ -1935,13 +1933,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (is_blank_ident(name)) {
error(token, "'using' cannot be applied variable declared as '_'");
} else if (is_type_struct(t) || is_type_raw_union(t)) {
- Scope *scope = scope_of_node(&c->info, t->Struct.node);
+ Scope *scope = scope_of_node(&ctx->checker->info, t->Struct.node);
for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
if (f->kind == Entity_Variable) {
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);
+ Entity *prev = scope_insert_entity(ctx->scope, uvar);
if (prev != nullptr) {
error(token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
return;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 3ccb30157..9e3a91a72 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -1,5 +1,5 @@
-void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *> *entity_map) {
+void populate_using_entity_map(CheckerContext *ctx, AstNode *node, Type *t, Map<Entity *> *entity_map) {
t = base_type(type_deref(t));
gbString str = nullptr;
defer (gb_string_free(str));
@@ -24,9 +24,9 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
}
} else {
map_set(entity_map, key, f);
- add_entity(c, c->context.scope, nullptr, f);
+ add_entity(ctx->checker, ctx->scope, nullptr, f);
if (f->flags & EntityFlag_Using) {
- populate_using_entity_map(c, node, f->type, entity_map);
+ populate_using_entity_map(ctx, node, f->type, entity_map);
}
}
}
@@ -34,12 +34,12 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *>
}
-void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Array<AstNode *> params,
+void check_struct_fields(CheckerContext *ctx, AstNode *node, Array<Entity *> *fields, Array<AstNode *> params,
isize init_field_capacity, Type *named_type, String context) {
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
Map<Entity *> entity_map = {};
- map_init(&entity_map, c->allocator, 2*init_field_capacity);
+ map_init(&entity_map, ctx->allocator, 2*init_field_capacity);
defer (map_destroy(&entity_map));
@@ -67,7 +67,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
if (type_expr != nullptr) {
- type = check_type_expr(c, type_expr, nullptr);
+ type = check_type_expr(ctx, type_expr, nullptr);
if (is_type_polymorphic(type)) {
type = nullptr;
}
@@ -95,8 +95,8 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
Token name_token = name->Ident.token;
- Entity *field = alloc_entity_field(c->context.scope, name_token, type, is_using, field_src_index);
- add_entity(c, c->context.scope, name, field);
+ Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
+ add_entity(ctx->checker, ctx->scope, name, field);
array_add(fields, field);
field_src_index += 1;
@@ -117,23 +117,23 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
continue;
}
- populate_using_entity_map(c, node, type, &entity_map);
+ populate_using_entity_map(ctx, node, type, &entity_map);
}
}
}
-Entity *make_names_field_for_struct(Checker *c, Scope *scope) {
+Entity *make_names_field_for_struct(CheckerContext *ctx, Scope *scope) {
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;
}
-bool check_custom_align(Checker *c, AstNode *node, i64 *align_) {
+bool check_custom_align(CheckerContext *ctx, AstNode *node, i64 *align_) {
GB_ASSERT(align_ != nullptr);
Operand o = {};
- check_expr(c, &o, node);
+ check_expr(ctx, &o, node);
if (o.mode != Addressing_Constant) {
if (o.mode != Addressing_Invalid) {
error(node, "#align must be a constant");
@@ -165,11 +165,11 @@ bool check_custom_align(Checker *c, AstNode *node, i64 *align_) {
}
-Entity *find_polymorphic_struct_entity(Checker *c, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
- gb_mutex_lock(&c->mutex);
- defer (gb_mutex_unlock(&c->mutex));
+Entity *find_polymorphic_struct_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> ordered_operands) {
+ gb_mutex_lock(&ctx->checker->mutex);
+ defer (gb_mutex_unlock(&ctx->checker->mutex));
- auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type));
+ auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
if (found_gen_types != nullptr) {
for_array(i, *found_gen_types) {
Entity *e = (*found_gen_types)[i];
@@ -208,10 +208,10 @@ Entity *find_polymorphic_struct_entity(Checker *c, Type *original_type, isize pa
}
-void add_polymorphic_struct_entity(Checker *c, AstNode *node, Type *named_type, Type *original_type) {
+void add_polymorphic_struct_entity(CheckerContext *ctx, AstNode *node, Type *named_type, Type *original_type) {
GB_ASSERT(is_type_named(named_type));
gbAllocator a = heap_allocator();
- Scope *s = c->context.scope->parent;
+ Scope *s = ctx->scope->parent;
Entity *e = nullptr;
{
@@ -225,22 +225,23 @@ void add_polymorphic_struct_entity(Checker *c, AstNode *node, Type *named_type,
e = alloc_entity_type_name(s, token, named_type);
e->state = EntityState_Resolved;
- add_entity_use(c, node, e);
+ e->pkg = ctx->pkg;
+ add_entity_use(ctx, node, e);
}
named_type->Named.type_name = e;
- auto *found_gen_types = map_get(&c->info.gen_types, hash_pointer(original_type));
+ auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type));
if (found_gen_types) {
array_add(found_gen_types, e);
} else {
auto array = array_make<Entity *>(heap_allocator());
array_add(&array, e);
- map_set(&c->info.gen_types, hash_pointer(original_type), array);
+ map_set(&ctx->checker->info.gen_types, hash_pointer(original_type), array);
}
}
-void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
+void check_struct_type(CheckerContext *ctx, Type *struct_type, AstNode *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
GB_ASSERT(is_type_struct(struct_type));
ast_node(st, StructType, node);
@@ -255,7 +256,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
case_end;
}
}
- struct_type->Struct.names = make_names_field_for_struct(c, c->context.scope);
+ struct_type->Struct.names = make_names_field_for_struct(ctx, ctx->scope);
if (st->is_raw_union) {
struct_type->Struct.is_raw_union = true;
@@ -280,7 +281,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
}
}
- auto entities = array_make<Entity *>(c->allocator, 0, variable_count);
+ auto entities = array_make<Entity *>(ctx->allocator, 0, variable_count);
for_array(i, params) {
AstNode *param = params[i];
@@ -305,7 +306,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
Type *specialization = nullptr;
if (type_expr->TypeType.specialization != nullptr) {
AstNode *s = type_expr->TypeType.specialization;
- specialization = check_type(c, s);
+ specialization = check_type(ctx, s);
// if (!is_type_polymorphic_struct(specialization)) {
// gbString str = type_to_string(specialization);
// defer (gb_string_free(str));
@@ -313,9 +314,9 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
// specialization = nullptr;
// }
}
- type = alloc_type_generic(c->context.scope, 0, str_lit(""), specialization);
+ type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
} else {
- type = check_type(c, type_expr);
+ type = check_type(ctx, type_expr);
if (is_type_polymorphic(type)) {
is_type_polymorphic_type = true;
}
@@ -347,7 +348,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
gb_string_free(str);
}
- Scope *scope = c->context.scope;
+ Scope *scope = ctx->scope;
for_array(j, p->names) {
AstNode *name = p->names[j];
if (!ast_node_expect(name, AstNode_Ident)) {
@@ -382,7 +383,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
}
e->state = EntityState_Resolved;
- add_entity(c, scope, name, e);
+ add_entity(ctx->checker, scope, name, e);
array_add(&entities, e);
}
}
@@ -396,7 +397,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
if (original_type_for_poly != nullptr) {
GB_ASSERT(named_type != nullptr);
- add_polymorphic_struct_entity(c, node, named_type, original_type_for_poly);
+ add_polymorphic_struct_entity(ctx, node, named_type, original_type_for_poly);
}
}
@@ -414,7 +415,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
}
}
- struct_type->Struct.scope = c->context.scope;
+ struct_type->Struct.scope = ctx->scope;
struct_type->Struct.is_packed = st->is_packed;
struct_type->Struct.polymorphic_params = polymorphic_params;
struct_type->Struct.is_polymorphic = is_polymorphic;
@@ -422,7 +423,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
if (!is_polymorphic) {
- check_struct_fields(c, node, &struct_type->Struct.fields, st->fields, min_field_count, named_type, context);
+ check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, named_type, context);
}
if (st->align != nullptr) {
@@ -431,12 +432,12 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
return;
}
i64 custom_align = 1;
- if (check_custom_align(c, st->align, &custom_align)) {
+ if (check_custom_align(ctx, st->align, &custom_align)) {
struct_type->Struct.custom_align = custom_align;
}
}
}
-void check_union_type(Checker *c, Type *union_type, AstNode *node) {
+void check_union_type(CheckerContext *ctx, Type *union_type, AstNode *node) {
GB_ASSERT(is_type_union(union_type));
ast_node(ut, UnionType, node);
@@ -444,13 +445,13 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
Entity *using_index_expr = nullptr;
- auto variants = array_make<Type *>(c->allocator, 0, variant_count);
+ auto variants = array_make<Type *>(ctx->allocator, 0, variant_count);
- union_type->Union.scope = c->context.scope;
+ union_type->Union.scope = ctx->scope;
for_array(i, ut->variants) {
AstNode *node = ut->variants[i];
- Type *t = check_type_expr(c, node, nullptr);
+ Type *t = check_type_expr(ctx, node, nullptr);
if (t != nullptr && t != t_invalid) {
bool ok = true;
t = default_type(t);
@@ -480,7 +481,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
if (ut->align != nullptr) {
i64 custom_align = 1;
- if (check_custom_align(c, ut->align, &custom_align)) {
+ if (check_custom_align(ctx, ut->align, &custom_align)) {
if (variants.count == 0) {
error(ut->align, "An empty union cannot have a custom alignment");
} else {
@@ -490,13 +491,13 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
}
}
-void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
+void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, AstNode *node) {
ast_node(et, EnumType, node);
GB_ASSERT(is_type_enum(enum_type));
Type *base_type = t_int;
if (et->base_type != nullptr) {
- base_type = check_type(c, et->base_type);
+ base_type = check_type(ctx, et->base_type);
}
if (base_type == nullptr || !(is_type_integer(base_type) || is_type_float(base_type))) {
@@ -510,13 +511,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
// NOTE(bill): Must be up here for the 'check_init_constant' system
enum_type->Enum.base_type = base_type;
- enum_type->Enum.scope = c->context.scope;
+ enum_type->Enum.scope = ctx->scope;
Map<Entity *> entity_map = {}; // Key: String
- map_init(&entity_map, c->allocator, 2*(et->fields.count));
+ map_init(&entity_map, ctx->allocator, 2*(et->fields.count));
defer (map_destroy(&entity_map));
- auto fields = array_make<Entity *>(c->allocator, 0, et->fields.count);
+ auto fields = array_make<Entity *>(ctx->allocator, 0, et->fields.count);
Type *constant_type = enum_type;
if (named_type != nullptr) {
@@ -549,13 +550,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
if (init != nullptr) {
Operand o = {};
- check_expr(c, &o, init);
+ check_expr(ctx, &o, init);
if (o.mode != Addressing_Constant) {
error(init, "Enumeration value must be a constant");
o.mode = Addressing_Invalid;
}
if (o.mode != Addressing_Invalid) {
- check_assignment(c, &o, constant_type, str_lit("enumeration"));
+ check_assignment(ctx, &o, constant_type, str_lit("enumeration"));
}
if (o.mode != Addressing_Invalid) {
iota = o.value;
@@ -594,7 +595,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
max_value = iota;
}
- Entity *e = alloc_entity_constant(c->context.scope, ident->Ident.token, constant_type, iota);
+ Entity *e = alloc_entity_constant(ctx->scope, ident->Ident.token, constant_type, iota);
e->identifier = ident;
e->flags |= EntityFlag_Visited;
e->state = EntityState_Resolved;
@@ -604,9 +605,9 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
error(ident, "'%.*s' is already declared in this enumeration", LIT(name));
} else {
map_set(&entity_map, key, e);
- add_entity(c, c->context.scope, nullptr, e);
+ add_entity(ctx->checker, ctx->scope, nullptr, e);
array_add(&fields, e);
- add_entity_use(c, field, e);
+ add_entity_use(ctx, field, e);
}
}
GB_ASSERT(fields.count <= et->fields.count);
@@ -615,7 +616,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
enum_type->Enum.fields = fields;
enum_type->Enum.is_export = et->is_export;
if (et->is_export) {
- Scope *parent = c->context.scope->parent;
+ Scope *parent = ctx->scope->parent;
for_array(i, fields) {
Entity *f = fields[i];
if (f->kind != Entity_Constant) {
@@ -625,30 +626,30 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
if (is_blank_ident(name)) {
continue;
}
- add_entity(c, parent, nullptr, f);
+ add_entity(ctx->checker, parent, nullptr, f);
}
}
- Scope *s = c->context.scope;
+ Scope *s = ctx->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);
+ enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope);
}
-void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
+void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, AstNode *node) {
ast_node(bft, BitFieldType, node);
GB_ASSERT(is_type_bit_field(bit_field_type));
Map<Entity *> entity_map = {}; // Key: String
- map_init(&entity_map, c->allocator, 2*(bft->fields.count));
+ map_init(&entity_map, ctx->allocator, 2*(bft->fields.count));
defer (map_destroy(&entity_map));
- auto fields = array_make<Entity*>(c->allocator, 0, bft->fields.count);
- auto sizes = array_make<u32> (c->allocator, 0, bft->fields.count);
- auto offsets = array_make<u32> (c->allocator, 0, bft->fields.count);
+ auto fields = array_make<Entity*>(ctx->allocator, 0, bft->fields.count);
+ auto sizes = array_make<u32> (ctx->allocator, 0, bft->fields.count);
+ auto offsets = array_make<u32> (ctx->allocator, 0, bft->fields.count);
u32 curr_offset = 0;
for_array(i, bft->fields) {
@@ -664,7 +665,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
String name = ident->Ident.token.string;
Operand o = {};
- check_expr(c, &o, value);
+ check_expr(ctx, &o, value);
if (o.mode != Addressing_Constant) {
error(value, "Bit field bit size must be a constant");
continue;
@@ -692,8 +693,8 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
error(ident, "'%.*s' is already declared in this bit field", LIT(name));
} else {
map_set(&entity_map, key, e);
- add_entity(c, c->context.scope, nullptr, e);
- add_entity_use(c, field, e);
+ add_entity(ctx->checker, ctx->scope, nullptr, e);
+ add_entity_use(ctx, field, e);
array_add(&fields, e);
array_add(&offsets, curr_offset);
@@ -710,14 +711,14 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
if (bft->align != nullptr) {
i64 custom_align = 1;
- if (check_custom_align(c, bft->align, &custom_align)) {
+ if (check_custom_align(ctx, bft->align, &custom_align)) {
bit_field_type->BitField.custom_align = custom_align;
}
}
}
-bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, bool compound, bool modify_type) {
+bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
if (type == nullptr ||
type == t_invalid) {
return true;
@@ -747,7 +748,7 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
Entity *t_e = t_tuple->variables[i];
Type *st = s_e->type;
Type *tt = t_e->type;
- bool ok = is_polymorphic_type_assignable(c, st, tt, true, modify_type);
+ bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
}
if (modify_type) {
@@ -763,7 +764,7 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
type->kind != Type_Named) {
return false;
}
- if (is_polymorphic_type_assignable(c, base_type(specialization), base_type(type), compound, modify_type)) {
+ if (is_polymorphic_type_assignable(ctx, base_type(specialization), base_type(type), compound, modify_type)) {
return true;
}
@@ -771,15 +772,15 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
}
-Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand operand) {
- bool modify_type = !c->context.no_polymorphic_errors;
+Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand operand) {
+ bool modify_type = !ctx->no_polymorphic_errors;
if (!is_operand_value(operand)) {
if (modify_type) {
error(operand.expr, "Cannot determine polymorphic type from parameter");
}
return t_invalid;
}
- if (is_polymorphic_type_assignable(c, poly_type, operand.type, false, modify_type)) {
+ if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
return poly_type;
}
if (modify_type) {
@@ -793,12 +794,12 @@ Type *determine_type_from_polymorphic(Checker *c, Type *poly_type, Operand opera
}
-Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
+Type *check_get_params(CheckerContext *ctx, Scope *scope, AstNode *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
if (_params == nullptr) {
return nullptr;
}
- bool allow_polymorphic_types = c->context.allow_polymorphic_types;
+ bool allow_polymorphic_types = ctx->allow_polymorphic_types;
bool success = true;
ast_node(field_list, FieldList, _params);
@@ -835,7 +836,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
bool is_variadic = false;
isize variadic_index = -1;
bool is_c_vararg = false;
- auto variables = array_make<Entity *>(c->allocator, 0, variable_count);
+ auto variables = array_make<Entity *>(ctx->allocator, 0, variable_count);
for_array(i, params) {
AstNode *param = params[i];
if (param->kind != AstNode_Field) {
@@ -858,12 +859,12 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (type_expr == nullptr) {
if (default_value->kind == AstNode_BasicDirective &&
default_value->BasicDirective.name == "caller_location") {
- init_preload(c);
+ init_preload(ctx->checker);
default_is_location = true;
type = t_source_code_location;
} else {
Operand o = {};
- check_expr_or_type(c, &o, default_value);
+ check_expr_or_type(ctx, &o, default_value);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
@@ -874,15 +875,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (o.mode == Addressing_Value && is_type_proc(o.type)) {
Operand x = {};
if (default_value->kind == AstNode_Ident) {
- e = check_ident(c, &x, default_value, nullptr, nullptr, false);
+ e = check_ident(ctx, &x, default_value, nullptr, nullptr, false);
} else if (default_value->kind == AstNode_SelectorExpr) {
- e = check_selector(c, &x, default_value, nullptr);
+ e = check_selector(ctx, &x, default_value, nullptr);
}
}
if (e != nullptr && e->kind == Entity_Procedure) {
value = exact_value_procedure(e->identifier);
- add_entity_use(c, e->identifier, e);
+ add_entity_use(ctx, e->identifier, e);
} else {
error(default_value, "Default parameter must be a constant");
continue;
@@ -916,7 +917,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (type_expr->kind == AstNode_TypeType) {
ast_node(tt, TypeType, type_expr);
is_type_param = true;
- specialization = check_type(c, tt->specialization);
+ specialization = check_type(ctx, tt->specialization);
if (specialization == t_invalid){
specialization = nullptr;
}
@@ -932,16 +933,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
detemine_type_from_operand = true;
type = t_invalid;
} else {
- type = alloc_type_generic(c->context.scope, 0, str_lit(""), specialization);
+ type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization);
}
} else {
- bool prev = c->context.allow_polymorphic_types;
+ bool prev = ctx->allow_polymorphic_types;
if (operands != nullptr) {
- c->context.allow_polymorphic_types = true;
+ ctx->allow_polymorphic_types = true;
}
- type = check_type(c, type_expr);
+ type = check_type(ctx, type_expr);
- c->context.allow_polymorphic_types = prev;
+ ctx->allow_polymorphic_types = prev;
if (is_type_polymorphic(type)) {
is_type_polymorphic_type = true;
@@ -956,12 +957,12 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
Operand o = {};
if (default_value->kind == AstNode_BasicDirective &&
default_value->BasicDirective.name == "caller_location") {
- init_preload(c);
+ init_preload(ctx->checker);
default_is_location = true;
o.type = t_source_code_location;
o.mode = Addressing_Value;
} else {
- check_expr_with_type_hint(c, &o, default_value, type);
+ check_expr_with_type_hint(ctx, &o, default_value, type);
if (is_operand_nil(o)) {
default_is_nil = true;
@@ -973,15 +974,15 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (o.mode == Addressing_Value && is_type_proc(o.type)) {
Operand x = {};
if (default_value->kind == AstNode_Ident) {
- e = check_ident(c, &x, default_value, nullptr, nullptr, false);
+ e = check_ident(ctx, &x, default_value, nullptr, nullptr, false);
} else if (default_value->kind == AstNode_SelectorExpr) {
- e = check_selector(c, &x, default_value, nullptr);
+ e = check_selector(ctx, &x, default_value, nullptr);
}
}
if (e != nullptr && e->kind == Entity_Procedure) {
value = exact_value_procedure(e->identifier);
- add_entity_use(c, e->identifier, e);
+ add_entity_use(ctx, e->identifier, e);
} else {
error(default_value, "Default parameter must be a constant");
}
@@ -991,7 +992,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
}
}
- check_is_assignable_to(c, &o, type);
+ check_is_assignable_to(ctx, &o, type);
}
}
}
@@ -1050,7 +1051,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (o.mode == Addressing_Type) {
type = o.type;
} else {
- if (!c->context.no_polymorphic_errors) {
+ if (!ctx->no_polymorphic_errors) {
error(o.expr, "Expected a type to assign to the type parameter");
}
success = false;
@@ -1063,10 +1064,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
success = false;
type = t_invalid;
}
- bool modify_type = !c->context.no_polymorphic_errors;
+ bool modify_type = !ctx->no_polymorphic_errors;
- if (specialization != nullptr && !check_type_specialization_to(c, specialization, type, false, modify_type)) {
- if (!c->context.no_polymorphic_errors) {
+ if (specialization != nullptr && !check_type_specialization_to(ctx, specialization, type, false, modify_type)) {
+ if (!ctx->no_polymorphic_errors) {
gbString t = type_to_string(type);
gbString s = type_to_string(specialization);
error(o.expr, "Cannot convert type '%s' to the specialization '%s'", t, s);
@@ -1083,10 +1084,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (operands != nullptr && variables.count < operands->count) {
if (is_type_polymorphic_type) {
Operand op = (*operands)[variables.count];
- type = determine_type_from_polymorphic(c, type, op);
+ type = determine_type_from_polymorphic(ctx, type, op);
if (type == t_invalid) {
success = false;
- } else if (!c->context.no_polymorphic_errors) {
+ } else if (!ctx->no_polymorphic_errors) {
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
is_type_polymorphic_type = false;
}
@@ -1110,7 +1111,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
}
param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it
- add_entity(c, scope, name, param);
+ add_entity(ctx->checker, scope, name, param);
array_add(&variables, param);
}
}
@@ -1157,7 +1158,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
return tuple;
}
-Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
+Type *check_get_results(CheckerContext *ctx, Scope *scope, AstNode *_results) {
if (_results == nullptr) {
return nullptr;
}
@@ -1178,7 +1179,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
}
}
- auto variables = array_make<Entity *>(c->allocator, 0, variable_count);
+ auto variables = array_make<Entity *>(ctx->allocator, 0, variable_count);
for_array(i, results) {
ast_node(field, Field, results[i]);
AstNode *default_value = unparen_expr(field->default_value);
@@ -1188,7 +1189,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
Type *type = nullptr;
if (field->type == nullptr) {
Operand o = {};
- check_expr(c, &o, default_value);
+ check_expr(ctx, &o, default_value);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
@@ -1199,11 +1200,11 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
type = default_type(o.type);
} else {
- type = check_type(c, field->type);
+ type = check_type(ctx, field->type);
if (default_value != nullptr) {
Operand o = {};
- check_expr_with_type_hint(c, &o, default_value, type);
+ check_expr_with_type_hint(ctx, &o, default_value, type);
if (is_operand_nil(o)) {
default_is_nil = true;
@@ -1212,7 +1213,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
} else {
value = o.value;
}
- check_is_assignable_to(c, &o, type);
+ check_is_assignable_to(ctx, &o, type);
}
}
@@ -1257,7 +1258,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
param->Variable.default_value = value;
param->Variable.default_is_nil = default_is_nil;
array_add(&variables, param);
- add_entity(c, scope, name, param);
+ add_entity(ctx->checker, scope, name, param);
}
}
}
@@ -1473,23 +1474,24 @@ bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *a
}
// NOTE(bill): 'operands' is for generating non generic procedure type
-bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands) {
+bool check_procedure_type(CheckerContext *ctx, Type *type, AstNode *proc_type_node, Array<Operand> *operands) {
ast_node(pt, ProcType, proc_type_node);
- if (c->context.polymorphic_scope == nullptr && c->context.allow_polymorphic_types) {
- c->context.polymorphic_scope = c->context.scope;
+ if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) {
+ ctx->polymorphic_scope = ctx->scope;
}
- CheckerContext prev = c->context;
- defer (c->context = prev);
- c->context.curr_proc_sig = type;
+ CheckerContext c_ = *ctx;
+ CheckerContext *c = &c_;
+
+ c->curr_proc_sig = type;
bool variadic = false;
isize variadic_index = -1;
bool success = true;
isize specialization_count = 0;
- Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
- Type *results = check_get_results(c, c->context.scope, pt->results);
+ Type *params = check_get_params(c, c->scope, pt->params, &variadic, &variadic_index, &success, &specialization_count, operands);
+ Type *results = check_get_results(c, c->scope, pt->results);
isize param_count = 0;
@@ -1516,14 +1518,14 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
ProcCallingConvention cc = pt->calling_convention;
if (cc == ProcCC_ForeignBlockDefault) {
cc = ProcCC_CDecl;
- if (c->context.foreign_context.default_cc > 0) {
- cc = c->context.foreign_context.default_cc;
+ if (c->foreign_context.default_cc > 0) {
+ cc = c->foreign_context.default_cc;
}
}
GB_ASSERT(cc > 0);
type->Proc.node = proc_type_node;
- type->Proc.scope = c->context.scope;
+ type->Proc.scope = c->scope;
type->Proc.params = params;
type->Proc.param_count = cast(i32)param_count;
type->Proc.results = results;
@@ -1578,7 +1580,7 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array
}
-i64 check_array_count(Checker *c, Operand *o, AstNode *e) {
+i64 check_array_count(CheckerContext *ctx, Operand *o, AstNode *e) {
if (e == nullptr) {
return 0;
}
@@ -1587,9 +1589,9 @@ i64 check_array_count(Checker *c, Operand *o, AstNode *e) {
return -1;
}
- check_expr_or_type(c, o, e);
+ check_expr_or_type(ctx, o, e);
if (o->mode == Addressing_Type && o->type->kind == Type_Generic) {
- if (c->context.allow_polymorphic_types) {
+ if (ctx->allow_polymorphic_types) {
if (o->type->Generic.specialized) {
o->type->Generic.specialized = nullptr;
error(o->expr, "Polymorphic array length cannot have a specialization");
@@ -1703,12 +1705,12 @@ void init_map_internal_types(Type *type) {
type->Map.lookup_result_type = make_optional_ok_type(value);
}
-void check_map_type(Checker *c, Type *type, AstNode *node) {
+void check_map_type(CheckerContext *ctx, Type *type, AstNode *node) {
GB_ASSERT(type->kind == Type_Map);
ast_node(mt, MapType, node);
- Type *key = check_type(c, mt->key);
- Type *value = check_type(c, mt->value);
+ Type *key = check_type(ctx, mt->key);
+ Type *value = check_type(ctx, mt->value);
if (!is_type_valid_for_keys(key)) {
if (is_type_boolean(key)) {
@@ -1724,11 +1726,11 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
type->Map.value = value;
if (is_type_string(key)) {
- add_package_dependency(c, "runtime", "__default_hash_string");
+ add_package_dependency(ctx, "runtime", "__default_hash_string");
}
- init_preload(c);
+ init_preload(ctx->checker);
init_map_internal_types(type);
// error(node, "'map' types are not yet implemented");
@@ -1736,7 +1738,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
-bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) {
+bool check_type_internal(CheckerContext *ctx, AstNode *e, Type **type, Type *named_type) {
GB_ASSERT_NOT_NULL(type);
if (e == nullptr) {
*type = t_invalid;
@@ -1746,7 +1748,7 @@ 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);
+ Entity *entity = check_ident(ctx, &o, e, named_type, nullptr, false);
gbString err_str = nullptr;
defer (gb_string_free(err_str));
@@ -1756,7 +1758,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
break;
case Addressing_Type: {
*type = o.type;
- if (!c->context.in_polymorphic_specialization) {
+ if (!ctx->in_polymorphic_specialization) {
Type *t = base_type(o.type);
if (t != nullptr && is_type_polymorphic_struct_unspecialized(t)) {
err_str = expr_to_string(e);
@@ -1765,10 +1767,10 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
}
}
- // if (c->context.type_level == 0 && entity->state == EntityState_InProgress) {
+ // if (ctx->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];
+ // for_array(j, *ctx->type_path) {
+ // Entity *k = (*ctx->type_path)[j];
// error(k->token, "\t%.*s refers to", LIT(k->token.string));
// }
// error(entity->token, "\t%.*s", LIT(entity->token.string));
@@ -1790,13 +1792,13 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_end;
case_ast_node(ht, HelperType, e);
- return check_type_internal(c, ht->type, type, named_type);
+ return check_type_internal(ctx, ht->type, type, named_type);
case_end;
case_ast_node(dt, DistinctType, e);
error(e, "Invalid use of a distinct type");
// NOTE(bill): Treat it as a HelperType to remove errors
- return check_type_internal(c, dt->type, type, named_type);
+ return check_type_internal(ctx, dt->type, type, named_type);
case_end;
case_ast_node(pt, PolyType, e);
@@ -1810,22 +1812,16 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
Token token = ident->Ident.token;
Type *specific = nullptr;
if (pt->specialization != nullptr) {
- CheckerContext prev = c->context; defer (c->context = prev);
- c->context.in_polymorphic_specialization = true;
+ CheckerContext c = *ctx;
+ c.in_polymorphic_specialization = true;
AstNode *s = pt->specialization;
- specific = check_type(c, s);
- // if (!is_type_polymorphic_struct(specific)) {
- // gbString str = type_to_string(specific);
- // error(s, "Expected a polymorphic struct, got %s", str);
- // gb_string_free(str);
- // specific = nullptr;
- // }
+ specific = check_type(&c, s);
}
- Type *t = alloc_type_generic(c->context.scope, 0, token.string, specific);
- if (c->context.allow_polymorphic_types) {
- Scope *ps = c->context.polymorphic_scope;
- Scope *s = c->context.scope;
+ Type *t = alloc_type_generic(ctx->scope, 0, token.string, specific);
+ if (ctx->allow_polymorphic_types) {
+ Scope *ps = ctx->polymorphic_scope;
+ Scope *s = ctx->scope;
Scope *entity_scope = s;
if (ps != nullptr && ps != s) {
// TODO(bill): Is this check needed?
@@ -1835,8 +1831,8 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
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);
- add_entity(c, s, ident, e);
+ add_entity(ctx->checker, ps, ident, e);
+ add_entity(ctx->checker, s, ident, e);
} else {
error(ident, "Invalid use of a polymorphic parameter '$%.*s'", LIT(token.string));
*type = t_invalid;
@@ -1849,7 +1845,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_ast_node(se, SelectorExpr, e);
Operand o = {};
- check_selector(c, &o, e, nullptr);
+ check_selector(ctx, &o, e, nullptr);
gbString err_str;
switch (o.mode) {
@@ -1873,7 +1869,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_expr(c, pe->expr, named_type);
+ *type = check_type_expr(ctx, pe->expr, named_type);
set_base_type(named_type, *type);
return true;
case_end;
@@ -1881,14 +1877,14 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_ast_node(ue, UnaryExpr, e);
switch (ue->op.kind) {
case Token_Pointer:
- *type = alloc_type_pointer(check_type(c, ue->expr));
+ *type = alloc_type_pointer(check_type(ctx, ue->expr));
set_base_type(named_type, *type);
return true;
}
case_end;
case_ast_node(pt, PointerType, e);
- *type = alloc_type_pointer(check_type(c, pt->type));
+ *type = alloc_type_pointer(check_type(ctx, pt->type));
set_base_type(named_type, *type);
return true;
case_end;
@@ -1896,7 +1892,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_ast_node(at, ArrayType, e);
if (at->count != nullptr) {
Operand o = {};
- i64 count = check_array_count(c, &o, at->count);
+ i64 count = check_array_count(ctx, &o, at->count);
Type *generic_type = nullptr;
if (o.mode == Addressing_Type && o.type->kind == Type_Generic) {
generic_type = o.type;
@@ -1905,10 +1901,10 @@ 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_expr(c, at->elem, nullptr);
+ Type *elem = check_type_expr(ctx, at->elem, nullptr);
*type = alloc_type_array(elem, count, generic_type);
} else {
- Type *elem = check_type(c, at->elem);
+ Type *elem = check_type(ctx, at->elem);
*type = alloc_type_slice(elem);
}
set_base_type(named_type, *type);
@@ -1916,50 +1912,50 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_end;
case_ast_node(dat, DynamicArrayType, e);
- Type *elem = check_type(c, dat->elem);
+ Type *elem = check_type(ctx, dat->elem);
*type = alloc_type_dynamic_array(elem);
set_base_type(named_type, *type);
return true;
case_end;
case_ast_node(st, StructType, e);
- CheckerContext prev = c->context; defer (c->context = prev);
- c->context.in_polymorphic_specialization = false;
- c->context.type_level += 1;
+ CheckerContext c = *ctx;
+ c.in_polymorphic_specialization = false;
+ c.type_level += 1;
*type = alloc_type_struct();
set_base_type(named_type, *type);
- check_open_scope(c, e);
- check_struct_type(c, *type, e, nullptr, named_type);
- check_close_scope(c);
+ check_open_scope(&c, e);
+ check_struct_type(&c, *type, e, nullptr, named_type);
+ check_close_scope(&c);
(*type)->Struct.node = e;
return true;
case_end;
case_ast_node(ut, UnionType, e);
- CheckerContext prev = c->context; defer (c->context = prev);
- c->context.in_polymorphic_specialization = false;
- c->context.type_level += 1;
+ CheckerContext c = *ctx;
+ c.in_polymorphic_specialization = false;
+ c.type_level += 1;
*type = alloc_type_union();
set_base_type(named_type, *type);
- check_open_scope(c, e);
- check_union_type(c, *type, e);
- check_close_scope(c);
+ check_open_scope(&c, e);
+ check_union_type(&c, *type, e);
+ check_close_scope(&c);
(*type)->Union.node = e;
return true;
case_end;
case_ast_node(et, EnumType, e);
- bool ips = c->context.in_polymorphic_specialization;
- defer (c->context.in_polymorphic_specialization = ips);
- c->context.in_polymorphic_specialization = false;
+ bool ips = ctx->in_polymorphic_specialization;
+ defer (ctx->in_polymorphic_specialization = ips);
+ ctx->in_polymorphic_specialization = false;
*type = alloc_type_enum();
set_base_type(named_type, *type);
- check_open_scope(c, e);
- check_enum_type(c, *type, named_type, e);
- check_close_scope(c);
+ check_open_scope(ctx, e);
+ check_enum_type(ctx, *type, named_type, e);
+ check_close_scope(ctx);
(*type)->Enum.node = e;
return true;
case_end;
@@ -1967,39 +1963,39 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_ast_node(et, BitFieldType, e);
*type = alloc_type_bit_field();
set_base_type(named_type, *type);
- check_open_scope(c, e);
- check_bit_field_type(c, *type, e);
- check_close_scope(c);
+ check_open_scope(ctx, e);
+ check_bit_field_type(ctx, *type, e);
+ check_close_scope(ctx);
return true;
case_end;
case_ast_node(pt, ProcType, e);
- bool ips = c->context.in_polymorphic_specialization;
- defer (c->context.in_polymorphic_specialization = ips);
- c->context.in_polymorphic_specialization = false;
+ bool ips = ctx->in_polymorphic_specialization;
+ defer (ctx->in_polymorphic_specialization = ips);
+ ctx->in_polymorphic_specialization = false;
*type = alloc_type(Type_Proc);
set_base_type(named_type, *type);
- check_open_scope(c, e);
- check_procedure_type(c, *type, e);
- check_close_scope(c);
+ check_open_scope(ctx, e);
+ check_procedure_type(ctx, *type, e);
+ check_close_scope(ctx);
return true;
case_end;
case_ast_node(mt, MapType, e);
- bool ips = c->context.in_polymorphic_specialization;
- defer (c->context.in_polymorphic_specialization = ips);
- c->context.in_polymorphic_specialization = false;
+ bool ips = ctx->in_polymorphic_specialization;
+ defer (ctx->in_polymorphic_specialization = ips);
+ ctx->in_polymorphic_specialization = false;
*type = alloc_type(Type_Map);
set_base_type(named_type, *type);
- check_map_type(c, *type, e);
+ check_map_type(ctx, *type, e);
return true;
case_end;
case_ast_node(ce, CallExpr, e);
Operand o = {};
- check_expr_or_type(c, &o, e);
+ check_expr_or_type(ctx, &o, e);
if (o.mode == Addressing_Type) {
*type = o.type;
set_base_type(named_type, *type);
@@ -2009,7 +2005,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
case_ast_node(te, TernaryExpr, e);
Operand o = {};
- check_expr_or_type(c, &o, e);
+ check_expr_or_type(ctx, &o, e);
if (o.mode == Addressing_Type) {
*type = o.type;
set_base_type(named_type, *type);
@@ -2022,17 +2018,17 @@ 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));
+Type *check_type(CheckerContext *ctx, AstNode *e) {
+ CheckerContext c = *ctx;
+ c.type_path = new_checker_type_path();
+ defer (destroy_checker_type_path(c.type_path));
- return check_type_expr(c, e, nullptr);
+ return check_type_expr(&c, e, nullptr);
}
-Type *check_type_expr(Checker *c, AstNode *e, Type *named_type) {
+Type *check_type_expr(CheckerContext *ctx, AstNode *e, Type *named_type) {
Type *type = nullptr;
- bool ok = check_type_internal(c, e, &type, named_type);
+ bool ok = check_type_internal(ctx, e, &type, named_type);
if (!ok) {
gbString err_str = expr_to_string(e);
@@ -2055,7 +2051,7 @@ Type *check_type_expr(Checker *c, AstNode *e, Type *named_type) {
}
#if 0
- if (!c->context.allow_polymorphic_types && is_type_polymorphic(type)) {
+ if (!ctx->allow_polymorphic_types && is_type_polymorphic(type)) {
gbString str = type_to_string(type);
error(e, "Invalid use of a polymorphic type '%s'", str);
gb_string_free(str);
@@ -2064,7 +2060,7 @@ Type *check_type_expr(Checker *c, AstNode *e, Type *named_type) {
#endif
if (is_type_typed(type)) {
- add_type_and_value(&c->info, e, Addressing_Type, type, empty_exact_value);
+ add_type_and_value(&ctx->checker->info, e, Addressing_Type, type, empty_exact_value);
} else {
gbString name = type_to_string(type);
error(e, "Invalid type definition of %s", name);
diff --git a/src/checker.cpp b/src/checker.cpp
index d6b564027..7791420e4 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -1,7 +1,7 @@
#include "entity.cpp"
#include "types.cpp"
-void check_expr(Checker *c, Operand *operand, AstNode *expression);
+void check_expr(CheckerContext *c, Operand *operand, AstNode *expression);
bool is_operand_value(Operand o) {
@@ -229,7 +229,7 @@ Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_ca
return s;
}
-Scope *create_scope_from_file(Checker *c, AstFile *f) {
+Scope *create_scope_from_file(CheckerContext *c, AstFile *f) {
GB_ASSERT(f != nullptr);
GB_ASSERT(f->pkg != nullptr);
GB_ASSERT(f->pkg->scope != nullptr);
@@ -246,7 +246,7 @@ Scope *create_scope_from_file(Checker *c, AstFile *f) {
return s;
}
-Scope *create_scope_from_package(Checker *c, AstPackage *p) {
+Scope *create_scope_from_package(CheckerContext *c, AstPackage *p) {
GB_ASSERT(p != nullptr);
isize decl_count = 0;
@@ -254,14 +254,13 @@ Scope *create_scope_from_package(Checker *c, AstPackage *p) {
decl_count += p->files[i]->decls.count;
}
isize init_elements_capacity = 2*decl_count;
-
Scope *s = create_scope(universal_scope, c->allocator, init_elements_capacity);
s->is_package = true;
s->package = p;
p->scope = s;
- if (p->fullpath == c->parser->init_fullpath) {
+ if (p->fullpath == c->checker->parser->init_fullpath) {
s->is_init = true;
} else {
s->is_init = p->kind == Package_Init;
@@ -306,7 +305,7 @@ void destroy_scope(Scope *scope) {
}
-void add_scope(Checker *c, AstNode *node, Scope *scope) {
+void add_scope(CheckerContext *c, AstNode *node, Scope *scope) {
GB_ASSERT(node != nullptr);
GB_ASSERT(scope != nullptr);
scope->node = node;
@@ -314,12 +313,12 @@ void add_scope(Checker *c, AstNode *node, Scope *scope) {
}
-void check_open_scope(Checker *c, AstNode *node) {
+void check_open_scope(CheckerContext *c, AstNode *node) {
node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) ||
is_ast_node_type(node));
- Scope *scope = create_scope(c->context.scope, c->allocator);
+ Scope *scope = create_scope(c->scope, c->allocator);
add_scope(c, node, scope);
switch (node->kind) {
case AstNode_ProcType:
@@ -331,12 +330,12 @@ void check_open_scope(Checker *c, AstNode *node) {
scope->is_struct = true;
break;
}
- c->context.scope = scope;
- c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
+ c->scope = scope;
+ c->stmt_state_flags |= StmtStateFlag_bounds_check;
}
-void check_close_scope(Checker *c) {
- c->context.scope = c->context.scope->parent;
+void check_close_scope(CheckerContext *c) {
+ c->scope = c->scope->parent;
}
@@ -488,7 +487,7 @@ void add_dependency(DeclInfo *d, Entity *e) {
}
void add_type_info_dependency(DeclInfo *d, Type *type) {
if (d == nullptr) {
- GB_ASSERT(type == t_invalid);
+ // GB_ASSERT(type == t_invalid);
return;
}
ptr_set_add(&d->type_info_deps, type);
@@ -505,22 +504,22 @@ AstPackage *get_core_package(CheckerInfo *info, String name) {
}
-void add_package_dependency(Checker *c, char *package_name, char *name) {
+void add_package_dependency(CheckerContext *c, char *package_name, char *name) {
String n = make_string_c(name);
- AstPackage *p = get_core_package(&c->info, make_string_c(package_name));
+ AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name));
Entity *e = scope_lookup_entity(p->scope, n);
GB_ASSERT(e != nullptr);
- ptr_set_add(&c->context.decl->deps, e);
+ ptr_set_add(&c->decl->deps, e);
// add_type_info_type(c, e->type);
}
-void add_declaration_dependency(Checker *c, Entity *e) {
+void add_declaration_dependency(CheckerContext *c, Entity *e) {
if (e == nullptr) {
return;
}
- if (c->context.decl != nullptr) {
+ if (c->decl != nullptr) {
// DeclInfo *decl = decl_info_of_entity(&c->info, e);
- add_dependency(c->context.decl, e);
+ add_dependency(c->decl, e);
}
}
@@ -641,6 +640,20 @@ void destroy_checker_info(CheckerInfo *i) {
array_free(&i->variable_init_order);
}
+CheckerContext make_checker_context(Checker *c) {
+ CheckerContext ctx = c->init_ctx;
+ ctx.checker = c;
+ ctx.allocator = c->allocator;
+ ctx.scope = universal_scope;
+
+ ctx.type_path = new_checker_type_path();
+ ctx.type_level = 0;
+ return ctx;
+}
+
+void destroy_checker_context(CheckerContext *ctx) {
+ destroy_checker_type_path(ctx->type_path);
+}
void init_checker(Checker *c, Parser *parser) {
if (global_error_collector.count > 0) {
@@ -658,10 +671,8 @@ void init_checker(Checker *c, Parser *parser) {
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
isize total_token_count = c->parser->total_token_count;
isize arena_size = 2 * item_size * total_token_count;
- // gb_arena_init_from_allocator(&c->tmp_arena, a, arena_size);
c->allocator = heap_allocator();
- // c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
isize pkg_cap = 2*c->parser->packages.count;
@@ -669,12 +680,7 @@ void init_checker(Checker *c, Parser *parser) {
array_init(&c->package_order, heap_allocator(), 0, c->parser->packages.count);
- // Init context
- c->context.checker = c;
- c->context.scope = universal_scope;
-
- c->context.type_path = new_checker_type_path();
- c->context.type_level = 0;
+ c->init_ctx = make_checker_context(c);
}
void destroy_checker(Checker *c) {
@@ -688,7 +694,7 @@ void destroy_checker(Checker *c) {
map_destroy(&c->package_scopes);
array_free(&c->package_order);
- destroy_checker_type_path(c->context.type_path);
+ destroy_checker_context(&c->init_ctx);
}
@@ -913,7 +919,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return true;
}
-void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
+void add_entity_use(CheckerContext *c, AstNode *identifier, Entity *entity) {
if (entity == nullptr) {
return;
}
@@ -936,7 +942,7 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
}
-void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) {
+void add_entity_and_decl_info(CheckerContext *c, AstNode *identifier, Entity *e, DeclInfo *d) {
GB_ASSERT(identifier->kind == AstNode_Ident);
GB_ASSERT(e != nullptr && d != nullptr);
GB_ASSERT(identifier->Ident.token.string == e->token.string);
@@ -952,25 +958,25 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
default: {
AstPackage *pkg = scope->file->pkg;
GB_ASSERT(pkg->scope == scope->parent);
- GB_ASSERT(c->context.pkg == pkg);
+ GB_ASSERT(c->pkg == pkg);
scope = pkg->scope;
break;
}
}
}
- add_entity(c, scope, identifier, e);
+ add_entity(c->checker, scope, identifier, e);
}
- add_entity_definition(&c->info, identifier, e);
+ add_entity_definition(&c->checker->info, identifier, e);
GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d;
- array_add(&c->info.entities, e);
- e->order_in_src = c->info.entities.count;
- e->pkg = c->context.pkg;
+ array_add(&c->checker->info.entities, e);
+ e->order_in_src = c->checker->info.entities.count;
+ e->pkg = c->pkg;
}
-void add_implicit_entity(Checker *c, AstNode *clause, Entity *e) {
+void add_implicit_entity(CheckerContext *c, AstNode *clause, Entity *e) {
GB_ASSERT(clause != nullptr);
GB_ASSERT(e != nullptr);
GB_ASSERT(clause->kind == AstNode_CaseClause);
@@ -981,7 +987,7 @@ void add_implicit_entity(Checker *c, AstNode *clause, Entity *e) {
-void add_type_info_type(Checker *c, Type *t) {
+void add_type_info_type(CheckerContext *c, Type *t) {
if (t == nullptr) {
return;
}
@@ -996,17 +1002,17 @@ void add_type_info_type(Checker *c, Type *t) {
return;
}
- auto found = map_get(&c->info.type_info_map, hash_type(t));
+ auto found = map_get(&c->checker->info.type_info_map, hash_type(t));
if (found != nullptr) {
// Types have already been added
- add_type_info_dependency(c->context.decl, t);
+ add_type_info_dependency(c->decl, t);
return;
}
bool prev = false;
isize ti_index = -1;
- for_array(i, c->info.type_info_map.entries) {
- auto *e = &c->info.type_info_map.entries[i];
+ for_array(i, c->checker->info.type_info_map.entries) {
+ auto *e = &c->checker->info.type_info_map.entries[i];
Type *prev_type = cast(Type *)e->key.ptr;
if (are_types_identical(t, prev_type)) {
// Duplicate entry
@@ -1018,14 +1024,14 @@ void add_type_info_type(Checker *c, Type *t) {
if (ti_index < 0) {
// Unique entry
// NOTE(bill): map entries grow linearly and in order
- ti_index = c->info.type_info_types.count;
- array_add(&c->info.type_info_types, t);
+ ti_index = c->checker->info.type_info_types.count;
+ array_add(&c->checker->info.type_info_types, t);
}
- map_set(&c->info.type_info_map, hash_type(t), ti_index);
+ map_set(&c->checker->info.type_info_map, hash_type(t), ti_index);
if (prev) {
// NOTE(bill): If a previous one exists already, no need to continue
- add_type_info_dependency(c->context.decl, t);
+ add_type_info_dependency(c->decl, t);
return;
}
@@ -1148,14 +1154,14 @@ void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *dec
check_procedure_later(c, info);
}
-void add_curr_ast_file(Checker *c, AstFile *file) {
+void add_curr_ast_file(CheckerContext *ctx, AstFile *file) {
if (file != nullptr) {
TokenPos zero_pos = {};
global_error_collector.prev = zero_pos;
- c->context.file = file;
- c->context.decl = file->pkg->decl_info;
- c->context.scope = file->scope;
- c->context.pkg = file->pkg;
+ ctx->file = file;
+ ctx->decl = file->pkg->decl_info;
+ ctx->scope = file->scope;
+ ctx->pkg = file->pkg;
}
}
@@ -1530,22 +1536,22 @@ void destroy_checker_type_path(CheckerTypePath *tp) {
}
-void check_type_path_push(Checker *c, Entity *e) {
- GB_ASSERT(c->context.type_path != nullptr);
+void check_type_path_push(CheckerContext *c, Entity *e) {
+ GB_ASSERT(c->type_path != nullptr);
GB_ASSERT(e != nullptr);
- array_add(c->context.type_path, e);
+ array_add(c->type_path, e);
}
-Entity *check_type_path_pop(Checker *c) {
- GB_ASSERT(c->context.type_path != nullptr);
- return array_pop(c->context.type_path);
+Entity *check_type_path_pop(CheckerContext *c) {
+ GB_ASSERT(c->type_path != nullptr);
+ return array_pop(c->type_path);
}
-void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type);
+void check_entity_decl(CheckerContext *c, Entity *e, DeclInfo *d, Type *named_type);
-Array<Entity *> proc_group_entities(Checker *c, Operand o) {
+Array<Entity *> proc_group_entities(CheckerContext *c, Operand o) {
Array<Entity *> procs = {};
if (o.mode == Addressing_ProcGroup) {
GB_ASSERT(o.proc_group != nullptr);
@@ -1681,7 +1687,7 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
if (cc == ProcCC_Invalid) {
error(elem, "Unknown procedure calling convention: '%.*s'\n", LIT(value.value_string));
} else {
- c->context.foreign_context.default_cc = cc;
+ c->foreign_context.default_cc = cc;
}
} else {
error(elem, "Expected a string value for '%.*s'", LIT(name));
@@ -1693,7 +1699,7 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
if (!is_foreign_name_valid(link_prefix)) {
error(elem, "Invalid link prefix: '%.*s'\n", LIT(link_prefix));
} else {
- c->context.foreign_context.link_prefix = link_prefix;
+ c->foreign_context.link_prefix = link_prefix;
}
} else {
error(elem, "Expected a string value for '%.*s'", LIT(name));
@@ -1742,7 +1748,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
DECL_ATTRIBUTE_PROC(var_decl_attribute) {
- if (c->context.curr_proc_decl != nullptr) {
+ if (c->curr_proc_decl != nullptr) {
error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name));
return true;
}
@@ -1770,7 +1776,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
} else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values");
- } else if (c->context.foreign_context.curr_library || c->context.foreign_context.in_export) {
+ } else if (c->foreign_context.curr_library || c->foreign_context.in_export) {
error(elem, "A foreign block variable cannot be thread local");
} else if (value.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default");
@@ -1801,7 +1807,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
-void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac) {
+void check_decl_attributes(CheckerContext *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac) {
if (attributes.count == 0) return;
String original_link_prefix = {};
@@ -1872,7 +1878,7 @@ void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttribut
}
-bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
+bool check_arity_match(CheckerContext *c, AstNodeValueDecl *vd, bool is_global) {
isize lhs = vd->names.count;
isize rhs = vd->values.count;
@@ -1908,7 +1914,7 @@ bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
return true;
}
-void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
+void check_collect_entities_from_when_stmt(CheckerContext *c, AstNodeWhenStmt *ws) {
Operand operand = {Addressing_Invalid};
if (!ws->is_cond_determined) {
check_expr(c, &operand, ws->cond);
@@ -1944,14 +1950,14 @@ void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws) {
}
}
-void check_collect_value_decl(Checker *c, AstNode *decl) {
+void check_collect_value_decl(CheckerContext *c, AstNode *decl) {
ast_node(vd, ValueDecl, decl);
if (vd->been_handled) return;
vd->been_handled = true;
if (vd->is_mutable) {
- if (!c->context.scope->is_file) {
+ if (!c->scope->is_file) {
// NOTE(bill): local scope -> handle later and in order
return;
}
@@ -1962,7 +1968,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
DeclInfo *di = nullptr;
if (vd->values.count > 0) {
- di = make_decl_info(heap_allocator(), c->context.scope, c->context.decl);
+ di = make_decl_info(heap_allocator(), c->scope, c->decl);
di->entities = entities;
di->type_expr = vd->type;
di->init_expr = vd->values[0];
@@ -1979,7 +1985,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 = alloc_entity_variable(c->context.scope, name->Ident.token, nullptr, false);
+ Entity *e = alloc_entity_variable(c->scope, name->Ident.token, nullptr, false);
e->identifier = name;
if (vd->is_using) {
@@ -1987,15 +1993,15 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
error(name, "'using' is not allowed at the file scope");
}
- AstNode *fl = c->context.foreign_context.curr_library;
+ AstNode *fl = c->foreign_context.curr_library;
if (fl != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident);
e->Variable.is_foreign = true;
e->Variable.foreign_library_ident = fl;
- e->Variable.link_prefix = c->context.foreign_context.link_prefix;
+ e->Variable.link_prefix = c->foreign_context.link_prefix;
- } else if (c->context.foreign_context.in_export) {
+ } else if (c->foreign_context.in_export) {
e->Variable.is_export = true;
}
@@ -2004,7 +2010,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
DeclInfo *d = di;
if (d == nullptr || i > 0) {
AstNode *init_expr = value;
- d = make_decl_info(heap_allocator(), e->scope, c->context.decl);
+ d = make_decl_info(heap_allocator(), e->scope, c->decl);
d->type_expr = vd->type;
d->init_expr = init_expr;
}
@@ -2034,8 +2040,8 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
Token token = name->Ident.token;
- AstNode *fl = c->context.foreign_context.curr_library;
- DeclInfo *d = make_decl_info(c->allocator, c->context.scope, c->context.decl);
+ AstNode *fl = c->foreign_context.curr_library;
+ DeclInfo *d = make_decl_info(c->allocator, c->scope, c->decl);
Entity *e = nullptr;
d->attributes = vd->attributes;
@@ -2049,7 +2055,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
d->type_expr = init;
d->init_expr = init;
} else if (init->kind == AstNode_ProcLit) {
- if (c->context.scope->is_struct) {
+ if (c->scope->is_struct) {
error(name, "Procedure declarations are not allowed within a struct");
continue;
}
@@ -2064,16 +2070,16 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
auto cc = pl->type->ProcType.calling_convention;
if (cc == ProcCC_ForeignBlockDefault) {
cc = ProcCC_CDecl;
- if (c->context.foreign_context.default_cc > 0) {
- cc = c->context.foreign_context.default_cc;
+ if (c->foreign_context.default_cc > 0) {
+ cc = c->foreign_context.default_cc;
}
}
- e->Procedure.link_prefix = c->context.foreign_context.link_prefix;
+ e->Procedure.link_prefix = c->foreign_context.link_prefix;
GB_ASSERT(cc != ProcCC_Invalid);
pl->type->ProcType.calling_convention = cc;
- } else if (c->context.foreign_context.in_export) {
+ } else if (c->foreign_context.in_export) {
e->Procedure.is_export = true;
}
d->proc_lit = init;
@@ -2093,7 +2099,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
e->identifier = name;
if (e->kind != Entity_Procedure) {
- if (fl != nullptr || c->context.foreign_context.in_export) {
+ if (fl != nullptr || c->foreign_context.in_export) {
AstNodeKind kind = init->kind;
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_node_strings[kind]));
if (kind == AstNode_ProcType) {
@@ -2110,7 +2116,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
}
}
-void check_add_foreign_block_decl(Checker *c, AstNode *decl) {
+void check_add_foreign_block_decl(CheckerContext *ctx, AstNode *decl) {
ast_node(fb, ForeignBlockDecl, decl);
if (fb->been_handled) return;
@@ -2118,36 +2124,35 @@ void check_add_foreign_block_decl(Checker *c, AstNode *decl) {
AstNode *foreign_library = fb->foreign_library;
- CheckerContext prev_context = c->context;
+ CheckerContext c = *ctx;
if (foreign_library->kind == AstNode_Ident) {
- c->context.foreign_context.curr_library = foreign_library;
+ c.foreign_context.curr_library = foreign_library;
} else if (foreign_library->kind == AstNode_Implicit && foreign_library->Implicit.kind == Token_export) {
- c->context.foreign_context.in_export = true;
+ c.foreign_context.in_export = true;
} else {
error(foreign_library, "Foreign block name must be an identifier or 'export'");
- c->context.foreign_context.curr_library = nullptr;
+ c.foreign_context.curr_library = nullptr;
}
- check_decl_attributes(c, fb->attributes, foreign_block_decl_attribute, nullptr);
+ check_decl_attributes(&c, fb->attributes, foreign_block_decl_attribute, nullptr);
- check_collect_entities(c, fb->decls);
- c->context = prev_context;
+ check_collect_entities(&c, fb->decls);
}
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope
-void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
+void check_collect_entities(CheckerContext *c, Array<AstNode *> nodes) {
for_array(decl_index, nodes) {
AstNode *decl = nodes[decl_index];
- if (c->context.scope->is_file) {
+ if (c->scope->is_file) {
}
if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) {
- if (c->context.scope->is_file && decl->kind == AstNode_ExprStmt) {
+ if (c->scope->is_file && decl->kind == AstNode_ExprStmt) {
AstNode *expr = decl->ExprStmt.expr;
if (expr->kind == AstNode_CallExpr &&
expr->CallExpr.proc->kind == AstNode_BasicDirective &&
expr->CallExpr.proc->BasicDirective.name == "assert") {
- array_add(&c->context.scope->delayed_asserts, expr);
+ array_add(&c->scope->delayed_asserts, expr);
continue;
}
}
@@ -2167,17 +2172,17 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
case_end;
case_ast_node(id, ImportDecl, decl);
- if (!c->context.scope->is_file) {
+ if (!c->scope->is_file) {
error(decl, "import declarations are only allowed in the file scope");
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
continue;
}
- array_add(&c->context.scope->delayed_imports, decl);
+ array_add(&c->scope->delayed_imports, decl);
case_end;
case_ast_node(fl, ForeignImportDecl, decl);
- if (!c->context.scope->is_file) {
+ if (!c->scope->is_file) {
error(decl, "%.*s declarations are only allowed in the file scope", LIT(fl->token.string));
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
@@ -2191,7 +2196,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
case_end;
default:
- if (c->context.scope->is_file) {
+ if (c->scope->is_file) {
error(decl, "Only declarations are allowed at file scope");
}
break;
@@ -2200,7 +2205,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
// NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source
- if (!c->context.scope->is_file) {
+ if (!c->scope->is_file) {
for_array(i, nodes) {
AstNode *node = nodes[i];
switch (node->kind) {
@@ -2215,8 +2220,8 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
void check_all_global_entities(Checker *c) {
Scope *prev_file = nullptr;
-
bool processing_preload = true;
+
for_array(i, c->info.entities) {
Entity *e = c->info.entities[i];
DeclInfo *d = e->decl_info;
@@ -2226,10 +2231,14 @@ void check_all_global_entities(Checker *c) {
}
+ CheckerContext ctx = c->init_ctx;
+
GB_ASSERT(d->scope->is_file);
AstFile *file = d->scope->file;
- add_curr_ast_file(c, file);
+ add_curr_ast_file(&ctx, file);
Scope *package_scope = file->pkg->scope;
+ GB_ASSERT(ctx.pkg != nullptr);
+ GB_ASSERT(e->pkg != nullptr);
if (e->token.string == "main") {
if (e->kind != Entity_Procedure) {
@@ -2243,11 +2252,9 @@ void check_all_global_entities(Checker *c) {
}
}
- CheckerContext prev_context = c->context;
- c->context.decl = d;
- c->context.scope = d->scope;
- check_entity_decl(c, e, d, nullptr);
- c->context = prev_context;
+ ctx.decl = d;
+ ctx.scope = d->scope;
+ check_entity_decl(&ctx, e, d, nullptr);
if (!package_scope->is_global) {
@@ -2490,19 +2497,24 @@ Array<ImportPathItem> find_import_path(Checker *c, Scope *start, Scope *end, Ptr
return empty_path;
}
#endif
-void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
+void check_add_import_decl(CheckerContext *ctx, AstNodeImportDecl *id) {
if (id->been_handled) return;
id->been_handled = true;
- Scope *parent_scope = c->context.scope;
+ gb_mutex_lock(&ctx->checker->mutex);
+ defer (gb_mutex_unlock(&ctx->checker->mutex));
+
+ Scope *parent_scope = ctx->scope;
GB_ASSERT(parent_scope->is_file);
+ auto *pkg_scopes = &ctx->checker->package_scopes;
+
Token token = id->relpath;
HashKey key = hash_string(id->fullpath);
- Scope **found = map_get(&c->package_scopes, key);
+ Scope **found = map_get(pkg_scopes, key);
if (found == nullptr) {
- for_array(scope_index, c->package_scopes.entries) {
- Scope *scope = c->package_scopes.entries[scope_index].value;
+ for_array(scope_index, pkg_scopes->entries) {
+ Scope *scope = pkg_scopes->entries[scope_index].value;
gb_printf_err("%.*s\n", LIT(scope->package->fullpath));
}
gb_printf_err("%.*s(%td:%td)\n", LIT(token.pos.file), token.pos.line, token.pos.column);
@@ -2542,9 +2554,9 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
id->fullpath, id->import_name.string,
scope);
- add_entity(c, parent_scope, nullptr, e);
+ add_entity(ctx->checker, parent_scope, nullptr, e);
if (id->is_using) {
- add_entity_use(c, nullptr, e);
+ add_entity_use(ctx, nullptr, e);
}
}
}
@@ -2578,8 +2590,8 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
if (is_entity_exported(e) && !implicit_is_found) {
- add_entity_use(c, node, e);
- bool ok = add_entity(c, parent_scope, e->identifier, e);
+ add_entity_use(ctx, node, e);
+ bool ok = add_entity(ctx->checker, parent_scope, e->identifier, e);
if (ok) ptr_set_add(&parent_scope->implicit, e);
} else {
error(node, "'%.*s' is exported from this scope", LIT(name));
@@ -2594,8 +2606,7 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
if (is_entity_exported(e) && !implicit_is_found) {
Entity *prev = scope_lookup_entity(parent_scope, e->token.string);
- // if (prev) gb_printf_err("%.*s\n", LIT(prev->token.string));
- bool ok = add_entity(c, parent_scope, e->identifier, e);
+ bool ok = add_entity(ctx->checker, parent_scope, e->identifier, e);
if (ok) ptr_set_add(&parent_scope->implicit, e);
}
}
@@ -2606,13 +2617,13 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
}
-void check_add_foreign_import_decl(Checker *c, AstNode *decl) {
+void check_add_foreign_import_decl(CheckerContext *ctx, AstNode *decl) {
ast_node(fl, ForeignImportDecl, decl);
if (fl->been_handled) return;
fl->been_handled = true;
- Scope *parent_scope = c->context.scope;
+ Scope *parent_scope = ctx->scope;
GB_ASSERT(parent_scope->is_file);
String fullpath = fl->fullpath;
@@ -2646,7 +2657,7 @@ void check_add_foreign_import_decl(Checker *c, AstNode *decl) {
fl->library_name.string = 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);
+ add_entity(ctx->checker, parent_scope, nullptr, e);
}
@@ -2733,25 +2744,24 @@ void check_import_entities(Checker *c) {
for_array(i, p->files) {
AstFile *f = p->files[i];
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
- add_curr_ast_file(c, f);
+ CheckerContext ctx = c->init_ctx;
+
+ add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_imports) {
AstNode *decl = f->scope->delayed_imports[j];
ast_node(id, ImportDecl, decl);
- check_add_import_decl(c, id);
+ check_add_import_decl(&ctx, id);
}
}
for_array(i, p->files) {
AstFile *f = p->files[i];
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
- add_curr_ast_file(c, f);
+ CheckerContext ctx = c->init_ctx;
+ add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_asserts) {
AstNode *expr = f->scope->delayed_asserts[j];
Operand o = {};
- check_expr(c, &o, expr);
+ check_expr(&ctx, &o, expr);
}
}
}
@@ -2913,13 +2923,13 @@ void check_parsed_files(Checker *c) {
TIME_SECTION("map full filepaths to scope");
- add_type_info_type(c, t_invalid);
+ add_type_info_type(&c->init_ctx, t_invalid);
// Map full filepaths to Scopes
for_array(i, c->parser->packages) {
AstPackage *p = c->parser->packages[i];
- Scope *scope = create_scope_from_package(c, p);
- p->decl_info = make_decl_info(c->allocator, scope, c->context.decl);
+ Scope *scope = create_scope_from_package(&c->init_ctx, p);
+ p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl);
HashKey key = hash_string(p->fullpath);
map_set(&c->package_scopes, key, scope);
map_set(&c->info.packages, key, p);
@@ -2937,17 +2947,20 @@ void check_parsed_files(Checker *c) {
// Collect Entities
for_array(i, c->parser->packages) {
AstPackage *p = c->parser->packages[i];
- CheckerContext prev_context = c->context;
+
+ CheckerContext ctx = make_checker_context(c);
+ defer (destroy_checker_context(&ctx));
+ ctx.pkg = p;
+
for_array(j, p->files) {
AstFile *f = p->files[j];
- create_scope_from_file(c, f);
+ create_scope_from_file(&ctx, f);
HashKey key = hash_string(f->fullpath);
map_set(&c->info.files, key, f);
- add_curr_ast_file(c, f);
- check_collect_entities(c, f->decls);
+ add_curr_ast_file(&ctx, f);
+ check_collect_entities(&ctx, f->decls);
}
- c->context = prev_context;
}
TIME_SECTION("import entities");
@@ -2959,6 +2972,9 @@ void check_parsed_files(Checker *c) {
TIME_SECTION("init preload");
init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of'
+ CheckerContext prev_context = c->init_ctx;
+ defer (c->init_ctx = prev_context);
+
TIME_SECTION("check procedure bodies");
// NOTE(bill): Nested procedures bodies will be added to this "queue"
for_array(i, c->procs_to_check) {
@@ -2966,8 +2982,10 @@ void check_parsed_files(Checker *c) {
if (pi->type == nullptr) {
continue;
}
- CheckerContext prev_context = c->context;
- defer (c->context = prev_context);
+
+ CheckerContext ctx = make_checker_context(c);
+ defer (destroy_checker_context(&ctx));
+ add_curr_ast_file(&ctx, pi->file);
TypeProc *pt = &pi->type->Proc;
String name = pi->token.string;
@@ -2975,22 +2993,22 @@ void check_parsed_files(Checker *c) {
GB_ASSERT_MSG(pt->is_poly_specialized, "%.*s", LIT(name));
}
- add_curr_ast_file(c, pi->file);
bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0;
if (bounds_check) {
- c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
- c->context.stmt_state_flags &= ~StmtStateFlag_no_bounds_check;
+ ctx.stmt_state_flags |= StmtStateFlag_bounds_check;
+ ctx.stmt_state_flags &= ~StmtStateFlag_no_bounds_check;
} else if (no_bounds_check) {
- c->context.stmt_state_flags |= StmtStateFlag_no_bounds_check;
- c->context.stmt_state_flags &= ~StmtStateFlag_bounds_check;
+ ctx.stmt_state_flags |= StmtStateFlag_no_bounds_check;
+ ctx.stmt_state_flags &= ~StmtStateFlag_bounds_check;
}
- check_proc_body(c, pi->token, pi->decl, pi->type, pi->body);
+ check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body);
}
+
for_array(i, c->info.files.entries) {
AstFile *f = c->info.files.entries[i].value;
check_scope_usage(c, f->scope);
@@ -3030,7 +3048,7 @@ void check_parsed_files(Checker *c) {
Type *t = &basic_types[i];
if (t->Basic.size > 0 &&
(t->Basic.flags & BasicFlag_LLVM) == 0) {
- add_type_info_type(c, t);
+ add_type_info_type(&c->init_ctx, t);
}
}
@@ -3041,7 +3059,7 @@ void check_parsed_files(Checker *c) {
// i64 size = type_size_of(c->allocator, e->type);
i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
- add_type_info_type(c, e->type);
+ add_type_info_type(&c->init_ctx, e->type);
}
}
}
diff --git a/src/checker.hpp b/src/checker.hpp
index 8d580ca97..b7fc2fc78 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -31,16 +31,19 @@ struct TypeAndValue {
// ExprInfo stores information used for "untyped" expressions
-struct ExprInfo : TypeAndValue {
+struct ExprInfo {
+ AddressingMode mode;
+ Type * type;
+ ExactValue value;
bool is_lhs; // Debug info
};
gb_inline ExprInfo make_expr_info(AddressingMode mode, Type *type, ExactValue value, bool is_lhs) {
ExprInfo ei = {};
- ei.is_lhs = is_lhs;
ei.mode = mode;
ei.type = type;
ei.value = value;
+ ei.is_lhs = is_lhs;
return ei;
}
@@ -289,6 +292,7 @@ struct CheckerContext {
DeclInfo * curr_proc_decl;
Type * curr_proc_sig;
ForeignContext foreign_context;
+ gbAllocator allocator;
CheckerTypePath *type_path;
isize type_level; // TODO(bill): Actually handle correctly
@@ -337,7 +341,7 @@ struct Checker {
gbAllocator allocator;
- CheckerContext context;
+ CheckerContext init_ctx;
bool done_preload;
};
@@ -379,20 +383,20 @@ void check_set_expr_info (CheckerInfo *i, AstNode *expr, ExprInfo info)
void check_remove_expr_info (CheckerInfo *i, AstNode *expr);
void add_untyped (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
void add_type_and_value (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value);
-void add_entity_use (Checker *c, AstNode *identifier, Entity *entity);
-void add_implicit_entity (Checker *c, AstNode *node, Entity *e);
-void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d);
-void add_type_info_type (Checker *c, Type *t);
+void add_entity_use (CheckerContext *c, AstNode *identifier, Entity *entity);
+void add_implicit_entity (CheckerContext *c, AstNode *node, Entity *e);
+void add_entity_and_decl_info(CheckerContext *c, AstNode *identifier, Entity *e, DeclInfo *d);
+void add_type_info_type (CheckerContext *c, Type *t);
-void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
+void check_add_import_decl(CheckerContext *c, AstNodeImportDecl *id);
// void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
-void check_add_foreign_import_decl(Checker *c, AstNode *decl);
+void check_add_foreign_import_decl(CheckerContext *c, AstNode *decl);
-bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false);
-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);
+bool check_arity_match(CheckerContext *c, AstNodeValueDecl *vd, bool is_global = false);
+void check_collect_entities(CheckerContext *c, Array<AstNode *> nodes);
+void check_collect_entities_from_when_stmt(CheckerContext *c, AstNodeWhenStmt *ws);
+void check_delayed_file_import_entity(CheckerContext *c, AstNode *decl);
struct AttributeContext {
String link_name;
@@ -408,13 +412,13 @@ AttributeContext make_attribute_context(String link_prefix) {
return ac;
}
-#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
+#define DECL_ATTRIBUTE_PROC(_name) bool _name(CheckerContext *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
-void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
+void check_decl_attributes(CheckerContext *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);
+void check_type_path_push(CheckerContext *c, Entity *e);
+Entity *check_type_path_pop (CheckerContext *c);
diff --git a/src/ir.cpp b/src/ir.cpp
index 87525028d..e773be111 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3833,14 +3833,16 @@ String ir_mangle_name(irGen *s, Entity *e) {
return make_string(new_name, new_name_len-1);
#else
- GB_ASSERT(e->pkg != nullptr);
- String pkg = e->pkg->name;
- GB_ASSERT(!rune_is_digit(pkg[0]));
-
String name = e->token.string;
+ AstPackage *pkg = e->pkg;
+ GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name));
+ String pkgn = pkg->name;
+ GB_ASSERT(!rune_is_digit(pkgn[0]));
+
+
- isize max_len = pkg.len + 1 + name.len + 1;
+ isize max_len = pkgn.len + 1 + name.len + 1;
bool require_suffix_id = is_type_polymorphic(e->type);
if (require_suffix_id) {
max_len += 21;
@@ -3849,7 +3851,7 @@ String ir_mangle_name(irGen *s, Entity *e) {
u8 *new_name = gb_alloc_array(a, u8, max_len);
isize new_name_len = gb_snprintf(
cast(char *)new_name, max_len,
- "%.*s.%.*s", LIT(pkg), LIT(name)
+ "%.*s.%.*s", LIT(pkgn), LIT(name)
);
if (require_suffix_id) {
char *str = cast(char *)new_name + new_name_len-1;