Refactor: use CheckerContext rather than Checker in type checking part

This commit is contained in:
gingerBill
2018-05-28 15:57:53 +01:00
parent 45b3067068
commit 642aa0bc4b
7 changed files with 799 additions and 785 deletions
+84 -87
View File
@@ -1,8 +1,8 @@
bool check_is_terminating(AstNode *node); 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 // 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 || if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid || operand->type == t_invalid ||
e->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) { if (e->type == nullptr) {
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string)); error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string));
} else { } 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) { if (operand->mode != Addressing_Type) {
return operand->type; return operand->type;
} }
@@ -79,9 +79,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
e->type = t; 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) { if (operand->mode == Addressing_Invalid) {
return nullptr; return nullptr;
} }
@@ -89,7 +89,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
return e->type; 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) { if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return; 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 // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation // 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)); 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; isize rhs_count = operands.count;
for_array(i, operands) { 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); isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) { for (isize i = 0; i < max; i++) {
Entity *e = lhs[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]; Operand *o = &operands[i];
check_init_variable(c, e, o, context_name); check_init_variable(ctx, e, o, context_name);
if (d != nullptr) { if (d != nullptr) {
d->init_expr = o->expr; 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 || if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid || operand->type == t_invalid ||
e->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; 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) { if (operand->mode == Addressing_Invalid) {
return; return;
} }
e->parent_proc_decl = c->context.curr_proc_decl; e->parent_proc_decl = ctx->curr_proc_decl;
e->Constant.value = operand->value; 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); 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) { if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on type declarations"); 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; e->type = named;
check_type_path_push(c, e); check_type_path_push(ctx, e);
Type *bt = check_type_expr(c, te, named); Type *bt = check_type_expr(ctx, te, named);
check_type_path_pop(c); check_type_path_pop(ctx);
named->Named.base = base_type(bt); named->Named.base = base_type(bt);
if (!is_distinct) { 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->type == nullptr);
GB_ASSERT(e->kind == Entity_Constant); 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; e->flags |= EntityFlag_Visited;
if (type_expr) { if (type_expr) {
Type *t = check_type(c, type_expr); Type *t = check_type(ctx, type_expr);
if (!is_type_constant_type(t)) { if (!is_type_constant_type(t)) {
gbString str = type_to_string(t); gbString str = type_to_string(t);
error(type_expr, "Invalid constant type '%s'", str); 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) { if (init != nullptr) {
Entity *entity = nullptr; Entity *entity = nullptr;
if (init->kind == AstNode_Ident) { 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) { } else if (init->kind == AstNode_SelectorExpr) {
entity = check_selector(c, &operand, init, e->type); entity = check_selector(ctx, &operand, init, e->type);
} else { } else {
check_expr_or_type(c, &operand, init, e->type); check_expr_or_type(ctx, &operand, init, e->type);
} }
switch (operand.mode) { 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->kind = Entity_TypeName;
e->type = nullptr; e->type = nullptr;
DeclInfo *d = c->context.decl; DeclInfo *d = ctx->decl;
if (d->type_expr != nullptr) { if (d->type_expr != nullptr) {
error(e->token, "A type declaration cannot have an type parameter"); error(e->token, "A type declaration cannot have an type parameter");
} }
d->type_expr = d->init_expr; 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; return;
} }
@@ -360,10 +360,10 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
} }
if (init != nullptr) { 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 || if (operand.mode == Addressing_Invalid ||
base_type(operand.type) == t_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) { if (decl != nullptr && decl->attributes.count > 0) {
error(decl->attributes[0], "Attributes are not allowed on constant value declarations"); 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; return true;
} }
void init_entity_foreign_library(Checker *c, Entity *e) { void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
AstNode *ident = nullptr; AstNode *ident = nullptr;
Entity **foreign_library = 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"); error(ident, "foreign library names must be an identifier");
} else { } else {
String name = ident->Ident.token.string; 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 (found == nullptr) {
if (is_blank_ident(name)) { if (is_blank_ident(name)) {
error(ident, "'_' cannot be used as a value type"); 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? // TODO(bill): Extra stuff to do with library names?
*foreign_library = found; *foreign_library = found;
found->LibraryName.used = true; 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_prefix.len > 0) {
if (link_name.len > 0) { if (link_name.len > 0) {
error(token, "'link_name' and 'link_prefix' cannot be used together"); error(token, "'link_name' and 'link_prefix' cannot be used together");
} else { } else {
isize len = link_prefix.len + token.string.len; 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[0], link_prefix.len);
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len); gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
name[len] = 0; name[len] = 0;
@@ -491,7 +491,7 @@ String handle_link_name(Checker *c, Token token, String link_name, String link_p
return link_name; 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); GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != AstNode_ProcLit) { if (d->proc_lit->kind != AstNode_ProcLit) {
// TOOD(bill): Better error message // TOOD(bill): Better error message
@@ -508,14 +508,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
e->type = proc_type; e->type = proc_type;
ast_node(pl, ProcLit, d->proc_lit); ast_node(pl, ProcLit, d->proc_lit);
check_open_scope(c, pl->type); check_open_scope(ctx, pl->type);
defer (check_close_scope(c)); defer (check_close_scope(ctx));
auto prev_context = c->context; auto tmp_ctx = *ctx;
c->context.allow_polymorphic_types = true; tmp_ctx.allow_polymorphic_types = true;
check_procedure_type(c, proc_type, pl->type); check_procedure_type(&tmp_ctx, proc_type, pl->type);
c->context = prev_context;
TypeProc *pt = &proc_type->Proc; 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); AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
if (d != nullptr) { 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; 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 (e->pkg != nullptr && e->token.string == "main") {
if (pt->param_count != 0 || if (pt->param_count != 0 ||
@@ -545,10 +544,10 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
} }
pt->calling_convention = ProcCC_Contextless; pt->calling_convention = ProcCC_Contextless;
if (e->pkg->kind == Package_Init) { 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'"); error(e->token, "Redeclaration of the entry pointer procedure 'main'");
} else { } 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"); 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); GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
if (!pt->is_polymorphic) { 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) { } else if (!is_foreign) {
if (e->Procedure.is_export) { 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.is_foreign = true;
e->Procedure.link_name = name; 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); HashKey key = hash_string(name);
Entity **found = map_get(fp, key); Entity **found = map_get(fp, key);
if (found) { if (found) {
@@ -642,7 +641,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
name = e->Procedure.link_name; name = e->Procedure.link_name;
} }
if (e->Procedure.link_name.len > 0 || is_export) { 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); HashKey key = hash_string(name);
Entity **found = map_get(fp, key); Entity **found = map_get(fp, key);
if (found) { 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->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable); 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); AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
ac.init_expr_list_count = init_expr_list.count; 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) { 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; e->Variable.thread_local_model = ac.thread_local_model;
String context_name = str_lit("variable declaration"); String context_name = str_lit("variable declaration");
if (type_expr != nullptr) { if (type_expr != nullptr) {
e->type = check_type(c, type_expr); e->type = check_type(ctx, type_expr);
} }
if (e->type != nullptr) { if (e->type != nullptr) {
if (is_type_polymorphic(base_type(e->type))) { 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) { if (init_expr_list.count > 0) {
error(e->token, "A foreign variable declaration cannot have a default value"); 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) { if (ac.link_name.len > 0) {
e->Variable.link_name = ac.link_name; 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) { if (e->Variable.link_name.len > 0) {
name = e->Variable.link_name; name = e->Variable.link_name;
} }
auto *fp = &c->info.foreigns; auto *fp = &ctx->checker->info.foreigns;
HashKey key = hash_string(name); HashKey key = hash_string(name);
Entity **found = map_get(fp, key); Entity **found = map_get(fp, key);
if (found) { 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); GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
auto *pge = &pg_entity->ProcGroup; auto *pge = &pg_entity->ProcGroup;
String proc_group_name = pg_entity->token.string; String proc_group_name = pg_entity->token.string;
ast_node(pg, ProcGroup, d->init_expr); 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 // NOTE(bill): This must be set here to prevent cycles in checking if someone
// places the entity within itself // places the entity within itself
@@ -775,9 +774,9 @@ void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
Entity *e = nullptr; Entity *e = nullptr;
Operand o = {}; Operand o = {};
if (arg->kind == AstNode_Ident) { 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) { } else if (arg->kind == AstNode_SelectorExpr) {
e = check_selector(c, &o, arg, nullptr); e = check_selector(ctx, &o, arg, nullptr);
} }
if (e == nullptr) { if (e == nullptr) {
error(arg, "Expected a valid entity name in procedure group, got %.*s", LIT(ast_node_strings[arg->kind])); 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) { if (e->state == EntityState_Resolved) {
return; return;
} }
@@ -893,7 +892,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
#endif #endif
if (d == nullptr) { if (d == nullptr) {
d = decl_info_of_entity(&c->info, e); d = decl_info_of_entity(&ctx->checker->info, e);
if (d == nullptr) { if (d == nullptr) {
// TODO(bill): Err here? // TODO(bill): Err here?
e->type = t_invalid; 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; CheckerContext c = *ctx;
c->context.scope = d->scope; c.scope = d->scope;
c->context.decl = d; c.decl = d;
c->context.type_level = 0; 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; e->state = EntityState_InProgress;
switch (e->kind) { switch (e->kind) {
case Entity_Variable: 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; break;
case Entity_Constant: 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; break;
case Entity_TypeName: { case Entity_TypeName: {
check_type_decl(c, e, d->type_expr, named_type); check_type_decl(&c, e, d->type_expr, named_type);
break; break;
} }
case Entity_Procedure: case Entity_Procedure:
check_proc_decl(c, e, d); check_proc_decl(&c, e, d);
break; break;
case Entity_ProcGroup: case Entity_ProcGroup:
check_proc_group_decl(c, e, d); check_proc_group_decl(&c, e, d);
break; break;
} }
e->state = EntityState_Resolved; e->state = EntityState_Resolved;
c->context = prev;
#undef TIME_SECTION #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) { if (body == nullptr) {
return; return;
} }
@@ -954,14 +951,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
proc_name = str_lit("(anonymous-procedure)"); proc_name = str_lit("(anonymous-procedure)");
} }
CheckerContext old_context = c->context; CheckerContext new_ctx = *ctx_;
defer (c->context = old_context); CheckerContext *ctx = &new_ctx;
c->context.scope = decl->scope; ctx->scope = decl->scope;
c->context.decl = decl; ctx->decl = decl;
c->context.proc_name = proc_name; ctx->proc_name = proc_name;
c->context.curr_proc_decl = decl; ctx->curr_proc_decl = decl;
c->context.curr_proc_sig = type; ctx->curr_proc_sig = type;
GB_ASSERT(type->kind == Type_Proc); GB_ASSERT(type->kind == Type_Proc);
if (type->Proc.param_count > 0) { 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) { if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope; Scope *scope = t->Struct.scope;
if (scope == nullptr) { 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); GB_ASSERT(scope != nullptr);
for_array(i, scope->elements.entries) { 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; uvar->Variable.is_immutable = is_immutable;
if (is_value) uvar->flags |= EntityFlag_Value; 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) { if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string)); error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
break; break;
@@ -1006,7 +1003,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
} }
ast_node(bs, BlockStmt, body); 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 (type->Proc.result_count > 0) {
if (!check_is_terminating(body)) { if (!check_is_terminating(body)) {
if (token.kind == Token_Ident) { 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) { if (decl->parent != nullptr) {
// NOTE(bill): Add the dependencies from the procedure literal (lambda) // NOTE(bill): Add the dependencies from the procedure literal (lambda)
+152 -153
View File
@@ -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); typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
void check_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr (CheckerContext *c, Operand *operand, AstNode *expression);
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_multi_expr (CheckerContext *c, Operand *operand, AstNode *expression);
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = nullptr); void check_expr_or_type (CheckerContext *c, Operand *operand, AstNode *expression, Type *type_hint = nullptr);
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); ExprKind check_expr_base (CheckerContext *c, Operand *operand, AstNode *expression, Type *type_hint);
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);
Type * check_type (Checker *c, AstNode *expression); Type * check_type (CheckerContext *c, AstNode *expression);
Type * check_type_expr (Checker *c, AstNode *expression, Type *named_type); Type * check_type_expr (CheckerContext *c, AstNode *expression, Type *named_type);
Type * make_optional_ok_type (Type *value); Type * make_optional_ok_type (Type *value);
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); void check_type_decl (CheckerContext *c, Entity *e, AstNode *type_expr, Type *def);
Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint); Entity * check_selector (CheckerContext *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 * check_ident (CheckerContext *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); Entity * find_polymorphic_struct_entity (CheckerContext *c, Type *original_type, isize param_count, Array<Operand> ordered_operands);
void check_not_tuple (Checker *c, Operand *operand); void check_not_tuple (CheckerContext *c, Operand *operand);
void convert_to_typed (Checker *c, Operand *operand, Type *target_type); void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type);
gbString expr_to_string (AstNode *expression); gbString expr_to_string (AstNode *expression);
void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); void check_entity_decl (CheckerContext *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_const_decl (CheckerContext *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 check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
void update_expr_type (Checker *c, AstNode *e, Type *type, bool final); void update_expr_type (CheckerContext *c, AstNode *e, Type *type, bool final);
bool check_is_terminating (AstNode *node); bool check_is_terminating (AstNode *node);
bool check_has_break (AstNode *stmt, bool implicit); bool check_has_break (AstNode *stmt, bool implicit);
void check_stmt (Checker *c, AstNode *node, u32 flags); void check_stmt (CheckerContext *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, Array<AstNode *> stmts, u32 flags); void check_stmt_list (CheckerContext *c, Array<AstNode *> stmts, u32 flags);
void check_init_constant (Checker *c, Entity *e, Operand *operand); void check_init_constant (CheckerContext *c, Entity *e, Operand *operand);
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);
bool check_procedure_type (Checker *c, Type *type, AstNode *proc_type_node, Array<Operand> *operands = nullptr); bool check_procedure_type (CheckerContext *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_struct_type (CheckerContext *c, Type *struct_type, AstNode *node, Array<Operand> *poly_operands,
Type *named_type = nullptr, Type *original_type_for_poly = nullptr); Type *named_type = nullptr, Type *original_type_for_poly = nullptr);
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);
Type * check_init_variable (Checker *c, Entity *e, Operand *operand, String context_name); 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) { void check_scope_decls(CheckerContext *c, Array<AstNode *> nodes, isize reserve_size) {
Scope *s = c->context.scope; Scope *s = c->scope;
GB_ASSERT(s->package == nullptr); GB_ASSERT(s->package == nullptr);
check_collect_entities(c, nodes); check_collect_entities(c, nodes);
@@ -123,7 +123,7 @@ void check_scope_decls(Checker *c, Array<AstNode *> nodes, isize reserve_size) {
default: default:
continue; continue;
} }
DeclInfo *d = decl_info_of_entity(&c->info, e); DeclInfo *d = decl_info_of_entity(&c->checker->info, e);
if (d != nullptr) { if (d != nullptr) {
check_entity_decl(c, e, 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; 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) { 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) { if (old_decl == nullptr) {
return false; return false;
} }
@@ -239,39 +239,38 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
CheckerContext prev_context = c->context; CheckerContext nctx = *c;
defer (c->context = prev_context);
Scope *scope = create_scope(base_entity->scope, a); Scope *scope = create_scope(base_entity->scope, a);
scope->is_proc = true; scope->is_proc = true;
c->context.scope = scope; nctx.scope = scope;
c->context.allow_polymorphic_types = true; nctx.allow_polymorphic_types = true;
if (c->context.polymorphic_scope == nullptr) { if (nctx.polymorphic_scope == nullptr) {
c->context.polymorphic_scope = scope; nctx.polymorphic_scope = scope;
} }
if (param_operands == nullptr) { 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; auto *pt = &src->Proc;
// NOTE(bill): This is slightly memory leaking if the type already exists // NOTE(bill): This is slightly memory leaking if the type already exists
// Maybe it's better to check with the previous types first? // 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); 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) { if (!success) {
return false; return false;
} }
gb_mutex_lock(&c->mutex); gb_mutex_lock(&nctx.checker->mutex);
defer (gb_mutex_unlock(&c->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) { if (found_gen_procs) {
auto procs = *found_gen_procs; auto procs = *found_gen_procs;
for_array(i, 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) { if (generate_type_again) {
// LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice // 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; bool prev_no_polymorphic_errors = nctx.no_polymorphic_errors;
defer (c->context.no_polymorphic_errors = prev_no_polymorphic_errors); defer (nctx.no_polymorphic_errors = prev_no_polymorphic_errors);
c->context.no_polymorphic_errors = false; nctx.no_polymorphic_errors = false;
// NOTE(bill): Reset scope from the failed procedure type // NOTE(bill): Reset scope from the failed procedure type
scope_reset(scope); 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) { if (!success) {
return false; 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); AstNode *proc_lit = clone_ast_node(a, old_decl->proc_lit);
ast_node(pl, ProcLit, proc_lit); ast_node(pl, ProcLit, proc_lit);
// NOTE(bill): Associate the scope declared above withinth this procedure declaration's type // 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_poly_specialized = true;
final_proc_type->Proc.is_polymorphic = true; final_proc_type->Proc.is_polymorphic = true;
u64 tags = base_entity->Procedure.tags; u64 tags = base_entity->Procedure.tags;
AstNode *ident = clone_ast_node(a, base_entity->identifier); AstNode *ident = clone_ast_node(a, base_entity->identifier);
Token token = ident->Ident.token; 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->gen_proc_type = final_proc_type;
d->type_expr = pl->type; d->type_expr = pl->type;
d->proc_lit = proc_lit; d->proc_lit = proc_lit;
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
entity->identifier = ident; 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 // NOTE(bill): Set the scope afterwards as this is not real overloading
entity->scope = scope->parent; entity->scope = scope->parent;
entity->pkg = base_entity->pkg;
AstFile *file = nullptr; AstFile *file = nullptr;
{ {
@@ -365,7 +364,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
} else { } else {
auto array = array_make<Entity *>(heap_allocator()); auto array = array_make<Entity *>(heap_allocator());
array_add(&array, entity); 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); 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 // NOTE(bill): Check the newly generated procedure body
check_procedure_later(c, proc_info); check_procedure_later(nctx.checker, proc_info);
return true; 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; 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; if (base_entity == nullptr) return false;
return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_proc_data); 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); 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 check_type_specialization_to(CheckerContext *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 is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type);
bool check_cast_internal(Checker *c, Operand *x, Type *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 || if (operand->mode == Addressing_Invalid ||
type == t_invalid) { type == t_invalid) {
return -1; return -1;
@@ -529,7 +528,7 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
#endif #endif
if (is_type_polymorphic(dst) && !is_type_polymorphic(src)) { 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)) { if (is_polymorphic_type_assignable(c, type, s, false, modify_type)) {
return 2; 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 score = 0;
i64 distance = check_distance_between_types(c, operand, type); i64 distance = check_distance_between_types(c, operand, type);
bool ok = distance >= 0; 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; i64 score = 0;
return check_is_assignable_to_with_score(c, operand, type, &score); return check_is_assignable_to_with_score(c, operand, type, &score);
} }
// NOTE(bill): 'content_name' is for debugging and error messages // 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); check_not_tuple(c, operand);
if (operand->mode == Addressing_Invalid) { if (operand->mode == Addressing_Invalid) {
return; 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}; Operand o = {Addressing_Value};
o.type = source; o.type = source;
switch (poly->kind) { switch (poly->kind) {
@@ -903,17 +902,17 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
return false; 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) { if (curr->state != EntityState_InProgress) {
return false; return false;
} }
for_array(i, *c->context.type_path) { for_array(i, *c->type_path) {
Entity *prev = (*c->context.type_path)[i]; Entity *prev = (*c->type_path)[i];
if (prev == curr) { if (prev == curr) {
if (report) { if (report) {
error(curr->token, "Illegal declaration cycle of `%.*s`", LIT(curr->token.string)); error(curr->token, "Illegal declaration cycle of `%.*s`", LIT(curr->token.string));
for (isize j = i; j < c->context.type_path->count; j++) { for (isize j = i; j < c->type_path->count; j++) {
Entity *curr = (*c->context.type_path)[j]; Entity *curr = (*c->type_path)[j];
error(curr->token, "\t%.*s refers to", LIT(curr->token.string)); error(curr->token, "\t%.*s refers to", LIT(curr->token.string));
} }
error(curr->token, "\t%.*s", 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); GB_ASSERT(n->kind == AstNode_Ident);
o->mode = Addressing_Invalid; o->mode = Addressing_Invalid;
o->expr = n; o->expr = n;
String name = n->Ident.token.string; 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 (e == nullptr) {
if (is_blank_ident(name)) { if (is_blank_ident(name)) {
error(n, "'_' cannot be used as a value type"); 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; return nullptr;
} }
if (e->parent_proc_decl != 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) { if (e->kind == Entity_Variable) {
error(n, "Nested procedures do not capture its parent's variables: %.*s", LIT(name)); error(n, "Nested procedures do not capture its parent's variables: %.*s", LIT(name));
return nullptr; return nullptr;
@@ -967,7 +966,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
if (e->kind == Entity_ProcGroup) { if (e->kind == Entity_ProcGroup) {
auto *pge = &e->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); 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) { if (o->type == nullptr) {
gbString str = expr_to_string(o->expr); gbString str = expr_to_string(o->expr);
error(o->expr, "Expression has no value '%s'", str); 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; 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 // TODO(bill): Handle errors correctly
Type *type = base_type(core_array_type(o->type)); Type *type = base_type(core_array_type(o->type));
switch (op.kind) { 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) { if (in_value.kind == ExactValue_Invalid) {
// NOTE(bill): There's already been an error // NOTE(bill): There's already been an error
return true; return true;
@@ -1340,7 +1339,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
return false; 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(is_type_constant_type(type));
GB_ASSERT(o->mode == Addressing_Constant); GB_ASSERT(o->mode == Addressing_Constant);
if (!check_representable_as_constant(c, o->value, type, &o->value)) { 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) { if (o->mode == Addressing_OptionalOk) {
AstNode *expr = unselector_expr(o->expr); AstNode *expr = unselector_expr(o->expr);
if (expr->kind != AstNode_TypeAssertion) { if (expr->kind != AstNode_TypeAssertion) {
return true; return true;
} }
ast_node(ta, TypeAssertion, expr); 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)) { if (is_type_pointer(tv.type)) {
return false; return false;
} }
@@ -1400,7 +1399,7 @@ bool check_is_not_addressable(Checker *c, Operand *o) {
return false; 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) { switch (op.kind) {
case Token_And: { // Pointer address case Token_And: { // Pointer address
if (check_is_not_addressable(c, o)) { 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) { if (x->mode == Addressing_Type && y->mode == Addressing_Type) {
bool comp = are_types_identical(x->type, y->type); bool comp = are_types_identical(x->type, y->type);
switch (op) { 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); GB_ASSERT(node->kind == AstNode_BinaryExpr);
ast_node(be, BinaryExpr, node); 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; TokenPos pos = ast_node_token(x->expr).pos;
if (x_is_untyped) { 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) { if (info != nullptr) {
info->is_lhs = true; 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); GB_ASSERT(node->kind == AstNode_BinaryExpr);
ast_node(be, BinaryExpr, node); ast_node(be, BinaryExpr, node);
GB_ASSERT(is_type_pointer(ptr->type)); 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)) { if (check_is_assignable_to(c, operand, y)) {
return true; return true;
} }
@@ -1865,7 +1864,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
return false; 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 is_const_expr = x->mode == Addressing_Constant;
bool can_convert = false; 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)) { if (!is_operand_value(*x)) {
error(x->expr, "Only values can be casted"); error(x->expr, "Only values can be casted");
x->mode = Addressing_Invalid; x->mode = Addressing_Invalid;
@@ -1924,7 +1923,7 @@ void check_cast(Checker *c, Operand *x, Type *type) {
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)) { if (!is_operand_value(*o)) {
error(o->expr, "'transmute' can only be applied to values"); error(o->expr, "'transmute' can only be applied to values");
o->mode = Addressing_Invalid; o->mode = Addressing_Invalid;
@@ -1967,7 +1966,7 @@ bool check_transmute(Checker *c, AstNode *node, Operand *o, Type *t) {
return true; 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 (is_type_array(x->type) && !is_type_array(y->type)) {
if (check_is_assignable_to(c, y, x->type)) { if (check_is_assignable_to(c, y, x->type)) {
if (check_binary_op(c, x, op)) { 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); GB_ASSERT(node->kind == AstNode_BinaryExpr);
Operand y_ = {}, *y = &y_; 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) { void update_expr_type(CheckerContext *c, AstNode *e, Type *type, bool final) {
ExprInfo *found = check_get_expr_info(&c->info, e); ExprInfo *found = check_get_expr_info(&c->checker->info, e);
if (found == nullptr) { if (found == nullptr) {
return; return;
} }
@@ -2207,12 +2206,12 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
if (!final && is_type_untyped(type)) { if (!final && is_type_untyped(type)) {
old.type = base_type(type); old.type = base_type(type);
check_set_expr_info(&c->info, e, old); check_set_expr_info(&c->checker->info, e, old);
return; return;
} }
// We need to remove it and then give it a new one // 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)) { if (old.is_lhs && !is_type_integer(type)) {
gbString expr_str = expr_to_string(e); gbString expr_str = expr_to_string(e);
@@ -2223,17 +2222,17 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
return; 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) { void update_expr_value(CheckerContext *c, AstNode *e, ExactValue value) {
ExprInfo *found = check_get_expr_info(&c->info, e); ExprInfo *found = check_get_expr_info(&c->checker->info, e);
if (found) { if (found) {
found->value = value; 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 expr_str = expr_to_string(operand->expr);
gbString type_str = type_to_string(target_type); gbString type_str = type_to_string(target_type);
char *extra_text = ""; char *extra_text = "";
@@ -2269,7 +2268,7 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
return v; 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); GB_ASSERT_NOT_NULL(target_type);
if (operand->mode == Addressing_Invalid || if (operand->mode == Addressing_Invalid ||
operand->mode == Addressing_Type || 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); 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}; Operand operand = {Addressing_Invalid};
check_expr(c, &operand, index_value); check_expr(c, &operand, index_value);
if (operand.mode == Addressing_Invalid) { 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 && 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; i64 i = exact_value_to_integer(operand.value).value_integer;
if (i < 0) { if (i < 0) {
gbString expr_str = expr_to_string(operand.expr); 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; 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); ast_node(se, SelectorExpr, node);
bool check_op_expr = true; 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) { if (op_expr->kind == AstNode_Ident) {
String op_name = op_expr->Ident.token.string; 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; bool is_alias = false;
while (e != nullptr && e->kind == Entity_Alias) { 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; 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); GB_ASSERT(call->kind == AstNode_CallExpr);
ast_node(ce, CallExpr, call); ast_node(ce, CallExpr, call);
BuiltinProc *bp = &builtin_procs[id]; BuiltinProc *bp = &builtin_procs[id];
@@ -3365,7 +3364,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false; return false;
} }
// NOTE(bill): Prevent type cycles for procedure declarations // 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); gbString s = expr_to_string(o.expr);
error(o.expr, "Invalid cyclic type usage from 'type_of', got '%s'", s); error(o.expr, "Invalid cyclic type usage from 'type_of', got '%s'", s);
gb_string_free(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: { case BuiltinProc_type_info_of: {
// proc type_info_of(Type) -> ^Type_Info // 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"); 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 // NOTE(bill): The type information may not be setup yet
init_preload(c); init_preload(c->checker);
AstNode *expr = ce->args[0]; AstNode *expr = ce->args[0];
Operand o = {}; Operand o = {};
check_expr_or_type(c, &o, expr); 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: { case BuiltinProc_typeid_of: {
// proc typeid_of(Type) -> typeid // 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"); 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 // NOTE(bill): The type information may not be setup yet
init_preload(c); init_preload(c->checker);
AstNode *expr = ce->args[0]; AstNode *expr = ce->args[0];
Operand o = {}; Operand o = {};
check_expr_or_type(c, &o, expr); 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) { if (lhs != nullptr) {
for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) { for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) {
Entity *e = lhs[tuple_index + 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) { 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) { for_array(k, decl->deps.entries) {
Entity *dep = decl->deps.entries[k].ptr; Entity *dep = decl->deps.entries[k].ptr;
add_declaration_dependency(c, dep); // TODO(bill): Should this be here? 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; bool optional_ok = false;
isize tuple_index = 0; isize tuple_index = 0;
for_array(i, rhs) { for_array(i, rhs) {
CheckerContext prev_context = c->context; CheckerContext c_ = *ctx;
defer (c->context = prev_context); CheckerContext *c = &c_;
Operand o = {}; 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) { if (lhs != nullptr && tuple_index < lhs_count) {
// NOTE(bill): override DeclInfo for dependency // NOTE(bill): override DeclInfo for dependency
Entity *e = lhs[tuple_index]; Entity *e = lhs[tuple_index];
DeclInfo *decl = decl_info_of_entity(&c->info, e); DeclInfo *decl = decl_info_of_entity(&c->checker->info, e);
if (decl) c->context.decl = decl; if (decl) c->decl = decl;
type_hint = e->type; 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 && if (allow_ok && lhs_count == 2 && rhs.count == 1 &&
(o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) { (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) {
Type *tuple = make_optional_ok_type(o.type); 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 val = o;
Operand ok = o; Operand ok = o;
@@ -4547,7 +4546,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
return err; 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); ast_node(ce, CallExpr, call);
CallArgumentCheckerType *call_checker = check_call_arguments_internal; 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)) { if (pt != nullptr && is_type_proc(pt)) {
CallArgumentError err = CallArgumentError_None; CallArgumentError err = CallArgumentError_None;
CallArgumentData data = {}; CallArgumentData data = {};
CheckerContext prev_context = c->context; CheckerContext ctx = *c;
defer (c->context = prev_context);
c->context.no_polymorphic_errors = true;
c->context.allow_polymorphic_types = is_type_polymorphic(pt);
err = call_checker(c, call, pt, p, operands, CallArgumentMode_NoErrors, &data); ctx.no_polymorphic_errors = true;
ctx.allow_polymorphic_types = is_type_polymorphic(pt);
err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
if (err == CallArgumentError_None) { if (err == CallArgumentError_None) {
valids[valid_count].index = i; valids[valid_count].index = i;
@@ -4723,7 +4722,7 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t
ident = s; ident = s;
} }
Entity *e = entity_of_ident(&c->info, ident); Entity *e = entity_of_ident(&c->checker->info, ident);
CallArgumentData data = {}; CallArgumentData data = {};
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &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; 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); ast_node(ce, CallExpr, call);
Type *original_type = operand->type; 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); ast_node(ce, CallExpr, call);
if (ce->proc != nullptr && if (ce->proc != nullptr &&
ce->proc->kind == AstNode_BasicDirective) { 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->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc; operand->expr = ce->proc;
operand->type = t_invalid; 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 { } else {
GB_PANIC("Unhandled #%.*s", LIT(name)); 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); Type *ot = operand->type; GB_ASSERT(ot->kind == Type_Named);
Entity *e = ot->Named.type_name; Entity *e = ot->Named.type_name;
add_entity_use(c, ident, e); 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 { } else {
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
operand->type = t_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_expr_base(c, o, e, t);
check_not_tuple(c, o); check_not_tuple(c, o);
char *err_str = nullptr; char *err_str = nullptr;
@@ -5206,7 +5205,7 @@ bool ternary_compare_types(Type *x, Type *y) {
return are_types_identical(x, 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; ExprKind kind = Expr_Stmt;
o->mode = Addressing_Invalid; 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) case_ast_node(i, Implicit, node)
switch (i->kind) { switch (i->kind) {
case Token_context: case Token_context:
if (c->context.proc_name.len == 0) { if (c->proc_name.len == 0) {
error(node, "'context' is only allowed within procedures"); error(node, "'context' is only allowed within procedures");
return kind; return kind;
} }
init_preload(c); init_preload(c->checker);
o->mode = Addressing_Immutable; o->mode = Addressing_Immutable;
o->type = t_context; o->type = t_context;
break; break;
@@ -5299,16 +5298,16 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
o->type = t_untyped_integer; o->type = t_untyped_integer;
o->value = exact_value_i64(bd->token.pos.line); o->value = exact_value_i64(bd->token.pos.line);
} else if (bd->name == "procedure") { } 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"); error(node, "#procedure may only be used within procedures");
o->type = t_untyped_string; o->type = t_untyped_string;
o->value = exact_value_string(str_lit("")); o->value = exact_value_string(str_lit(""));
} else { } else {
o->type = t_untyped_string; 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") { } 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"); error(node, "#caller_location may only be used as a default argument parameter");
o->type = t_source_code_location; o->type = t_source_code_location;
o->mode = Addressing_Value; o->mode = Addressing_Value;
@@ -5324,26 +5323,27 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
case_end; case_end;
case_ast_node(pl, ProcLit, node); case_ast_node(pl, ProcLit, node);
CheckerContext prev_context = c->context; CheckerContext ctx = *c;
DeclInfo *decl = nullptr; DeclInfo *decl = nullptr;
Type *type = alloc_type(Type_Proc); 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; decl->proc_lit = node;
c->context.decl = decl; ctx.decl = decl;
if (pl->tags != 0) { if (pl->tags != 0) {
error(node, "A procedure literal cannot have tags"); error(node, "A procedure literal cannot have tags");
pl->tags = 0; // TODO(bill): Should I zero this?! 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)) { if (!is_type_proc(type)) {
gbString str = expr_to_string(node); gbString str = expr_to_string(node);
error(node, "Invalid procedure literal '%s'", str); error(node, "Invalid procedure literal '%s'", str);
gb_string_free(str); gb_string_free(str);
check_close_scope(c); check_close_scope(&ctx);
return kind; return kind;
} }
@@ -5352,11 +5352,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind; 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->mode = Addressing_Value;
o->type = type; o->type = type;
@@ -6210,7 +6209,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind; 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); ExprKind kind = check_expr_base_internal(c, o, node, type_hint);
Type *type = nullptr; Type *type = nullptr;
ExactValue value = {ExactValue_Invalid}; 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)) { 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 { } 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; 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); check_expr_base(c, o, e, nullptr);
switch (o->mode) { switch (o->mode) {
default: default:
@@ -6255,7 +6254,7 @@ void check_multi_expr(Checker *c, Operand *o, AstNode *e) {
o->mode = Addressing_Invalid; 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) { if (o->mode == Addressing_Value) {
// NOTE(bill): Tuples are not first class thus never named // NOTE(bill): Tuples are not first class thus never named
if (o->type->kind == Type_Tuple) { 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_multi_expr(c, o, e);
check_not_tuple(c, o); 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_expr_base(c, o, e, type_hint);
check_not_tuple(c, o); check_not_tuple(c, o);
error_operand_no_value(o); error_operand_no_value(o);
+181 -183
View File
File diff suppressed because it is too large Load Diff
+189 -193
View File
File diff suppressed because it is too large Load Diff
+164 -146
View File
@@ -1,7 +1,7 @@
#include "entity.cpp" #include "entity.cpp"
#include "types.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) { bool is_operand_value(Operand o) {
@@ -229,7 +229,7 @@ Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_ca
return s; 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 != nullptr);
GB_ASSERT(f->pkg != nullptr); GB_ASSERT(f->pkg != nullptr);
GB_ASSERT(f->pkg->scope != nullptr); GB_ASSERT(f->pkg->scope != nullptr);
@@ -246,7 +246,7 @@ Scope *create_scope_from_file(Checker *c, AstFile *f) {
return s; return s;
} }
Scope *create_scope_from_package(Checker *c, AstPackage *p) { Scope *create_scope_from_package(CheckerContext *c, AstPackage *p) {
GB_ASSERT(p != nullptr); GB_ASSERT(p != nullptr);
isize decl_count = 0; isize decl_count = 0;
@@ -254,14 +254,13 @@ Scope *create_scope_from_package(Checker *c, AstPackage *p) {
decl_count += p->files[i]->decls.count; decl_count += p->files[i]->decls.count;
} }
isize init_elements_capacity = 2*decl_count; isize init_elements_capacity = 2*decl_count;
Scope *s = create_scope(universal_scope, c->allocator, init_elements_capacity); Scope *s = create_scope(universal_scope, c->allocator, init_elements_capacity);
s->is_package = true; s->is_package = true;
s->package = p; s->package = p;
p->scope = s; p->scope = s;
if (p->fullpath == c->parser->init_fullpath) { if (p->fullpath == c->checker->parser->init_fullpath) {
s->is_init = true; s->is_init = true;
} else { } else {
s->is_init = p->kind == Package_Init; 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(node != nullptr);
GB_ASSERT(scope != nullptr); GB_ASSERT(scope != nullptr);
scope->node = node; 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); node = unparen_expr(node);
GB_ASSERT(node->kind == AstNode_Invalid || GB_ASSERT(node->kind == AstNode_Invalid ||
is_ast_node_stmt(node) || is_ast_node_stmt(node) ||
is_ast_node_type(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); add_scope(c, node, scope);
switch (node->kind) { switch (node->kind) {
case AstNode_ProcType: case AstNode_ProcType:
@@ -331,12 +330,12 @@ void check_open_scope(Checker *c, AstNode *node) {
scope->is_struct = true; scope->is_struct = true;
break; break;
} }
c->context.scope = scope; c->scope = scope;
c->context.stmt_state_flags |= StmtStateFlag_bounds_check; c->stmt_state_flags |= StmtStateFlag_bounds_check;
} }
void check_close_scope(Checker *c) { void check_close_scope(CheckerContext *c) {
c->context.scope = c->context.scope->parent; 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) { void add_type_info_dependency(DeclInfo *d, Type *type) {
if (d == nullptr) { if (d == nullptr) {
GB_ASSERT(type == t_invalid); // GB_ASSERT(type == t_invalid);
return; return;
} }
ptr_set_add(&d->type_info_deps, type); 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); 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); Entity *e = scope_lookup_entity(p->scope, n);
GB_ASSERT(e != nullptr); 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); // 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) { if (e == nullptr) {
return; return;
} }
if (c->context.decl != nullptr) { if (c->decl != nullptr) {
// DeclInfo *decl = decl_info_of_entity(&c->info, e); // 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); 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) { void init_checker(Checker *c, Parser *parser) {
if (global_error_collector.count > 0) { 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 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 total_token_count = c->parser->total_token_count;
isize arena_size = 2 * item_size * 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->allocator = heap_allocator();
// c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
isize pkg_cap = 2*c->parser->packages.count; 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); array_init(&c->package_order, heap_allocator(), 0, c->parser->packages.count);
// Init context c->init_ctx = make_checker_context(c);
c->context.checker = c;
c->context.scope = universal_scope;
c->context.type_path = new_checker_type_path();
c->context.type_level = 0;
} }
void destroy_checker(Checker *c) { void destroy_checker(Checker *c) {
@@ -688,7 +694,7 @@ void destroy_checker(Checker *c) {
map_destroy(&c->package_scopes); map_destroy(&c->package_scopes);
array_free(&c->package_order); 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; 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) { if (entity == nullptr) {
return; 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(identifier->kind == AstNode_Ident);
GB_ASSERT(e != nullptr && d != nullptr); GB_ASSERT(e != nullptr && d != nullptr);
GB_ASSERT(identifier->Ident.token.string == e->token.string); 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: { default: {
AstPackage *pkg = scope->file->pkg; AstPackage *pkg = scope->file->pkg;
GB_ASSERT(pkg->scope == scope->parent); GB_ASSERT(pkg->scope == scope->parent);
GB_ASSERT(c->context.pkg == pkg); GB_ASSERT(c->pkg == pkg);
scope = pkg->scope; scope = pkg->scope;
break; 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); GB_ASSERT(e->decl_info == nullptr);
e->decl_info = d; e->decl_info = d;
array_add(&c->info.entities, e); array_add(&c->checker->info.entities, e);
e->order_in_src = c->info.entities.count; e->order_in_src = c->checker->info.entities.count;
e->pkg = c->context.pkg; 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(clause != nullptr);
GB_ASSERT(e != nullptr); GB_ASSERT(e != nullptr);
GB_ASSERT(clause->kind == AstNode_CaseClause); 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) { if (t == nullptr) {
return; return;
} }
@@ -996,17 +1002,17 @@ void add_type_info_type(Checker *c, Type *t) {
return; 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) { if (found != nullptr) {
// Types have already been added // Types have already been added
add_type_info_dependency(c->context.decl, t); add_type_info_dependency(c->decl, t);
return; return;
} }
bool prev = false; bool prev = false;
isize ti_index = -1; isize ti_index = -1;
for_array(i, c->info.type_info_map.entries) { for_array(i, c->checker->info.type_info_map.entries) {
auto *e = &c->info.type_info_map.entries[i]; auto *e = &c->checker->info.type_info_map.entries[i];
Type *prev_type = cast(Type *)e->key.ptr; Type *prev_type = cast(Type *)e->key.ptr;
if (are_types_identical(t, prev_type)) { if (are_types_identical(t, prev_type)) {
// Duplicate entry // Duplicate entry
@@ -1018,14 +1024,14 @@ void add_type_info_type(Checker *c, Type *t) {
if (ti_index < 0) { if (ti_index < 0) {
// Unique entry // Unique entry
// NOTE(bill): map entries grow linearly and in order // NOTE(bill): map entries grow linearly and in order
ti_index = c->info.type_info_types.count; ti_index = c->checker->info.type_info_types.count;
array_add(&c->info.type_info_types, t); 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) { if (prev) {
// NOTE(bill): If a previous one exists already, no need to continue // 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; return;
} }
@@ -1148,14 +1154,14 @@ void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *dec
check_procedure_later(c, info); 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) { if (file != nullptr) {
TokenPos zero_pos = {}; TokenPos zero_pos = {};
global_error_collector.prev = zero_pos; global_error_collector.prev = zero_pos;
c->context.file = file; ctx->file = file;
c->context.decl = file->pkg->decl_info; ctx->decl = file->pkg->decl_info;
c->context.scope = file->scope; ctx->scope = file->scope;
c->context.pkg = file->pkg; ctx->pkg = file->pkg;
} }
} }
@@ -1530,22 +1536,22 @@ void destroy_checker_type_path(CheckerTypePath *tp) {
} }
void check_type_path_push(Checker *c, Entity *e) { void check_type_path_push(CheckerContext *c, Entity *e) {
GB_ASSERT(c->context.type_path != nullptr); GB_ASSERT(c->type_path != nullptr);
GB_ASSERT(e != 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) { Entity *check_type_path_pop(CheckerContext *c) {
GB_ASSERT(c->context.type_path != nullptr); GB_ASSERT(c->type_path != nullptr);
return array_pop(c->context.type_path); 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 = {}; Array<Entity *> procs = {};
if (o.mode == Addressing_ProcGroup) { if (o.mode == Addressing_ProcGroup) {
GB_ASSERT(o.proc_group != nullptr); GB_ASSERT(o.proc_group != nullptr);
@@ -1681,7 +1687,7 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
if (cc == ProcCC_Invalid) { if (cc == ProcCC_Invalid) {
error(elem, "Unknown procedure calling convention: '%.*s'\n", LIT(value.value_string)); error(elem, "Unknown procedure calling convention: '%.*s'\n", LIT(value.value_string));
} else { } else {
c->context.foreign_context.default_cc = cc; c->foreign_context.default_cc = cc;
} }
} else { } else {
error(elem, "Expected a string value for '%.*s'", LIT(name)); 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)) { if (!is_foreign_name_valid(link_prefix)) {
error(elem, "Invalid link prefix: '%.*s'\n", LIT(link_prefix)); error(elem, "Invalid link prefix: '%.*s'\n", LIT(link_prefix));
} else { } else {
c->context.foreign_context.link_prefix = link_prefix; c->foreign_context.link_prefix = link_prefix;
} }
} else { } else {
error(elem, "Expected a string value for '%.*s'", LIT(name)); 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) { 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)); error(elem, "Only a variable at file scope can have a '%.*s'", LIT(name));
return true; return true;
} }
@@ -1770,7 +1776,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) {
} else if (name == "thread_local") { } else if (name == "thread_local") {
if (ac->init_expr_list_count > 0) { if (ac->init_expr_list_count > 0) {
error(elem, "A thread local variable declaration cannot have initialization values"); 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"); error(elem, "A foreign block variable cannot be thread local");
} else if (value.kind == ExactValue_Invalid) { } else if (value.kind == ExactValue_Invalid) {
ac->thread_local_model = str_lit("default"); 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; if (attributes.count == 0) return;
String original_link_prefix = {}; 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 lhs = vd->names.count;
isize rhs = vd->values.count; isize rhs = vd->values.count;
@@ -1908,7 +1914,7 @@ bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global) {
return true; 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}; Operand operand = {Addressing_Invalid};
if (!ws->is_cond_determined) { if (!ws->is_cond_determined) {
check_expr(c, &operand, ws->cond); 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); ast_node(vd, ValueDecl, decl);
if (vd->been_handled) return; if (vd->been_handled) return;
vd->been_handled = true; vd->been_handled = true;
if (vd->is_mutable) { if (vd->is_mutable) {
if (!c->context.scope->is_file) { if (!c->scope->is_file) {
// NOTE(bill): local scope -> handle later and in order // NOTE(bill): local scope -> handle later and in order
return; return;
} }
@@ -1962,7 +1968,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap); Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap);
DeclInfo *di = nullptr; DeclInfo *di = nullptr;
if (vd->values.count > 0) { 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->entities = entities;
di->type_expr = vd->type; di->type_expr = vd->type;
di->init_expr = vd->values[0]; 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])); error(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue; 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; e->identifier = name;
if (vd->is_using) { 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"); 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) { if (fl != nullptr) {
GB_ASSERT(fl->kind == AstNode_Ident); GB_ASSERT(fl->kind == AstNode_Ident);
e->Variable.is_foreign = true; e->Variable.is_foreign = true;
e->Variable.foreign_library_ident = fl; 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; e->Variable.is_export = true;
} }
@@ -2004,7 +2010,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
DeclInfo *d = di; DeclInfo *d = di;
if (d == nullptr || i > 0) { if (d == nullptr || i > 0) {
AstNode *init_expr = value; 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->type_expr = vd->type;
d->init_expr = init_expr; d->init_expr = init_expr;
} }
@@ -2034,8 +2040,8 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
Token token = name->Ident.token; Token token = name->Ident.token;
AstNode *fl = c->context.foreign_context.curr_library; AstNode *fl = c->foreign_context.curr_library;
DeclInfo *d = make_decl_info(c->allocator, c->context.scope, c->context.decl); DeclInfo *d = make_decl_info(c->allocator, c->scope, c->decl);
Entity *e = nullptr; Entity *e = nullptr;
d->attributes = vd->attributes; d->attributes = vd->attributes;
@@ -2049,7 +2055,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
d->type_expr = init; d->type_expr = init;
d->init_expr = init; d->init_expr = init;
} else if (init->kind == AstNode_ProcLit) { } 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"); error(name, "Procedure declarations are not allowed within a struct");
continue; continue;
} }
@@ -2064,16 +2070,16 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
auto cc = pl->type->ProcType.calling_convention; auto cc = pl->type->ProcType.calling_convention;
if (cc == ProcCC_ForeignBlockDefault) { if (cc == ProcCC_ForeignBlockDefault) {
cc = ProcCC_CDecl; cc = ProcCC_CDecl;
if (c->context.foreign_context.default_cc > 0) { if (c->foreign_context.default_cc > 0) {
cc = c->context.foreign_context.default_cc; 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); GB_ASSERT(cc != ProcCC_Invalid);
pl->type->ProcType.calling_convention = cc; 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; e->Procedure.is_export = true;
} }
d->proc_lit = init; d->proc_lit = init;
@@ -2093,7 +2099,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
e->identifier = name; e->identifier = name;
if (e->kind != Entity_Procedure) { 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; 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])); 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) { 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); ast_node(fb, ForeignBlockDecl, decl);
if (fb->been_handled) return; 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; AstNode *foreign_library = fb->foreign_library;
CheckerContext prev_context = c->context; CheckerContext c = *ctx;
if (foreign_library->kind == AstNode_Ident) { 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) { } 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 { } else {
error(foreign_library, "Foreign block name must be an identifier or 'export'"); 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); check_collect_entities(&c, fb->decls);
c->context = prev_context;
} }
// NOTE(bill): If file_scopes == nullptr, this will act like a local scope // 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) { for_array(decl_index, nodes) {
AstNode *decl = nodes[decl_index]; 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 (!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; AstNode *expr = decl->ExprStmt.expr;
if (expr->kind == AstNode_CallExpr && if (expr->kind == AstNode_CallExpr &&
expr->CallExpr.proc->kind == AstNode_BasicDirective && expr->CallExpr.proc->kind == AstNode_BasicDirective &&
expr->CallExpr.proc->BasicDirective.name == "assert") { expr->CallExpr.proc->BasicDirective.name == "assert") {
array_add(&c->context.scope->delayed_asserts, expr); array_add(&c->scope->delayed_asserts, expr);
continue; continue;
} }
} }
@@ -2167,17 +2172,17 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
case_end; case_end;
case_ast_node(id, ImportDecl, decl); 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"); error(decl, "import declarations are only allowed in the file scope");
// NOTE(bill): _Should_ be caught by the parser // NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't // TODO(bill): Better error handling if it isn't
continue; continue;
} }
array_add(&c->context.scope->delayed_imports, decl); array_add(&c->scope->delayed_imports, decl);
case_end; case_end;
case_ast_node(fl, ForeignImportDecl, decl); 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)); error(decl, "%.*s declarations are only allowed in the file scope", LIT(fl->token.string));
// NOTE(bill): _Should_ be caught by the parser // NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't // TODO(bill): Better error handling if it isn't
@@ -2191,7 +2196,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
case_end; case_end;
default: default:
if (c->context.scope->is_file) { if (c->scope->is_file) {
error(decl, "Only declarations are allowed at file scope"); error(decl, "Only declarations are allowed at file scope");
} }
break; 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 // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source // declared after this stmt in source
if (!c->context.scope->is_file) { if (!c->scope->is_file) {
for_array(i, nodes) { for_array(i, nodes) {
AstNode *node = nodes[i]; AstNode *node = nodes[i];
switch (node->kind) { switch (node->kind) {
@@ -2215,8 +2220,8 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes) {
void check_all_global_entities(Checker *c) { void check_all_global_entities(Checker *c) {
Scope *prev_file = nullptr; Scope *prev_file = nullptr;
bool processing_preload = true; bool processing_preload = true;
for_array(i, c->info.entities) { for_array(i, c->info.entities) {
Entity *e = c->info.entities[i]; Entity *e = c->info.entities[i];
DeclInfo *d = e->decl_info; 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); GB_ASSERT(d->scope->is_file);
AstFile *file = d->scope->file; AstFile *file = d->scope->file;
add_curr_ast_file(c, file); add_curr_ast_file(&ctx, file);
Scope *package_scope = file->pkg->scope; Scope *package_scope = file->pkg->scope;
GB_ASSERT(ctx.pkg != nullptr);
GB_ASSERT(e->pkg != nullptr);
if (e->token.string == "main") { if (e->token.string == "main") {
if (e->kind != Entity_Procedure) { if (e->kind != Entity_Procedure) {
@@ -2243,11 +2252,9 @@ void check_all_global_entities(Checker *c) {
} }
} }
CheckerContext prev_context = c->context; ctx.decl = d;
c->context.decl = d; ctx.scope = d->scope;
c->context.scope = d->scope; check_entity_decl(&ctx, e, d, nullptr);
check_entity_decl(c, e, d, nullptr);
c->context = prev_context;
if (!package_scope->is_global) { if (!package_scope->is_global) {
@@ -2490,19 +2497,24 @@ Array<ImportPathItem> find_import_path(Checker *c, Scope *start, Scope *end, Ptr
return empty_path; return empty_path;
} }
#endif #endif
void check_add_import_decl(Checker *c, AstNodeImportDecl *id) { void check_add_import_decl(CheckerContext *ctx, AstNodeImportDecl *id) {
if (id->been_handled) return; if (id->been_handled) return;
id->been_handled = true; 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); GB_ASSERT(parent_scope->is_file);
auto *pkg_scopes = &ctx->checker->package_scopes;
Token token = id->relpath; Token token = id->relpath;
HashKey key = hash_string(id->fullpath); HashKey key = hash_string(id->fullpath);
Scope **found = map_get(&c->package_scopes, key); Scope **found = map_get(pkg_scopes, key);
if (found == nullptr) { if (found == nullptr) {
for_array(scope_index, c->package_scopes.entries) { for_array(scope_index, pkg_scopes->entries) {
Scope *scope = c->package_scopes.entries[scope_index].value; Scope *scope = pkg_scopes->entries[scope_index].value;
gb_printf_err("%.*s\n", LIT(scope->package->fullpath)); 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); 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, id->fullpath, id->import_name.string,
scope); scope);
add_entity(c, parent_scope, nullptr, e); add_entity(ctx->checker, parent_scope, nullptr, e);
if (id->is_using) { 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); bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
if (is_entity_exported(e) && !implicit_is_found) { if (is_entity_exported(e) && !implicit_is_found) {
add_entity_use(c, node, e); add_entity_use(ctx, node, e);
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); if (ok) ptr_set_add(&parent_scope->implicit, e);
} else { } else {
error(node, "'%.*s' is exported from this scope", LIT(name)); 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); bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
if (is_entity_exported(e) && !implicit_is_found) { if (is_entity_exported(e) && !implicit_is_found) {
Entity *prev = scope_lookup_entity(parent_scope, e->token.string); 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(ctx->checker, parent_scope, e->identifier, e);
bool ok = add_entity(c, parent_scope, e->identifier, e);
if (ok) ptr_set_add(&parent_scope->implicit, 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); ast_node(fl, ForeignImportDecl, decl);
if (fl->been_handled) return; if (fl->been_handled) return;
fl->been_handled = true; fl->been_handled = true;
Scope *parent_scope = c->context.scope; Scope *parent_scope = ctx->scope;
GB_ASSERT(parent_scope->is_file); GB_ASSERT(parent_scope->is_file);
String fullpath = fl->fullpath; String fullpath = fl->fullpath;
@@ -2646,7 +2657,7 @@ void check_add_foreign_import_decl(Checker *c, AstNode *decl) {
fl->library_name.string = library_name; fl->library_name.string = library_name;
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid, Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
fl->fullpath, library_name); 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) { for_array(i, p->files) {
AstFile *f = p->files[i]; AstFile *f = p->files[i];
CheckerContext prev_context = c->context; CheckerContext ctx = c->init_ctx;
defer (c->context = prev_context);
add_curr_ast_file(c, f); add_curr_ast_file(&ctx, f);
for_array(j, f->scope->delayed_imports) { for_array(j, f->scope->delayed_imports) {
AstNode *decl = f->scope->delayed_imports[j]; AstNode *decl = f->scope->delayed_imports[j];
ast_node(id, ImportDecl, decl); ast_node(id, ImportDecl, decl);
check_add_import_decl(c, id); check_add_import_decl(&ctx, id);
} }
} }
for_array(i, p->files) { for_array(i, p->files) {
AstFile *f = p->files[i]; AstFile *f = p->files[i];
CheckerContext prev_context = c->context; CheckerContext ctx = c->init_ctx;
defer (c->context = prev_context); add_curr_ast_file(&ctx, f);
add_curr_ast_file(c, f);
for_array(j, f->scope->delayed_asserts) { for_array(j, f->scope->delayed_asserts) {
AstNode *expr = f->scope->delayed_asserts[j]; AstNode *expr = f->scope->delayed_asserts[j];
Operand o = {}; 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"); 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 // Map full filepaths to Scopes
for_array(i, c->parser->packages) { for_array(i, c->parser->packages) {
AstPackage *p = c->parser->packages[i]; AstPackage *p = c->parser->packages[i];
Scope *scope = create_scope_from_package(c, p); Scope *scope = create_scope_from_package(&c->init_ctx, p);
p->decl_info = make_decl_info(c->allocator, scope, c->context.decl); p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl);
HashKey key = hash_string(p->fullpath); HashKey key = hash_string(p->fullpath);
map_set(&c->package_scopes, key, scope); map_set(&c->package_scopes, key, scope);
map_set(&c->info.packages, key, p); map_set(&c->info.packages, key, p);
@@ -2937,17 +2947,20 @@ void check_parsed_files(Checker *c) {
// Collect Entities // Collect Entities
for_array(i, c->parser->packages) { for_array(i, c->parser->packages) {
AstPackage *p = c->parser->packages[i]; 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) { for_array(j, p->files) {
AstFile *f = p->files[j]; AstFile *f = p->files[j];
create_scope_from_file(c, f); create_scope_from_file(&ctx, f);
HashKey key = hash_string(f->fullpath); HashKey key = hash_string(f->fullpath);
map_set(&c->info.files, key, f); map_set(&c->info.files, key, f);
add_curr_ast_file(c, f); add_curr_ast_file(&ctx, f);
check_collect_entities(c, f->decls); check_collect_entities(&ctx, f->decls);
} }
c->context = prev_context;
} }
TIME_SECTION("import entities"); TIME_SECTION("import entities");
@@ -2959,6 +2972,9 @@ void check_parsed_files(Checker *c) {
TIME_SECTION("init preload"); TIME_SECTION("init preload");
init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of' init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of'
CheckerContext prev_context = c->init_ctx;
defer (c->init_ctx = prev_context);
TIME_SECTION("check procedure bodies"); TIME_SECTION("check procedure bodies");
// NOTE(bill): Nested procedures bodies will be added to this "queue" // NOTE(bill): Nested procedures bodies will be added to this "queue"
for_array(i, c->procs_to_check) { for_array(i, c->procs_to_check) {
@@ -2966,8 +2982,10 @@ void check_parsed_files(Checker *c) {
if (pi->type == nullptr) { if (pi->type == nullptr) {
continue; 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; TypeProc *pt = &pi->type->Proc;
String name = pi->token.string; 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)); 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 bounds_check = (pi->tags & ProcTag_bounds_check) != 0;
bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0;
if (bounds_check) { if (bounds_check) {
c->context.stmt_state_flags |= StmtStateFlag_bounds_check; ctx.stmt_state_flags |= StmtStateFlag_bounds_check;
c->context.stmt_state_flags &= ~StmtStateFlag_no_bounds_check; ctx.stmt_state_flags &= ~StmtStateFlag_no_bounds_check;
} else if (no_bounds_check) { } else if (no_bounds_check) {
c->context.stmt_state_flags |= StmtStateFlag_no_bounds_check; ctx.stmt_state_flags |= StmtStateFlag_no_bounds_check;
c->context.stmt_state_flags &= ~StmtStateFlag_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) { for_array(i, c->info.files.entries) {
AstFile *f = c->info.files.entries[i].value; AstFile *f = c->info.files.entries[i].value;
check_scope_usage(c, f->scope); check_scope_usage(c, f->scope);
@@ -3030,7 +3048,7 @@ void check_parsed_files(Checker *c) {
Type *t = &basic_types[i]; Type *t = &basic_types[i];
if (t->Basic.size > 0 && if (t->Basic.size > 0 &&
(t->Basic.flags & BasicFlag_LLVM) == 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 size = type_size_of(c->allocator, e->type);
i64 align = type_align_of(e->type); i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) { 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);
} }
} }
} }
+21 -17
View File
@@ -31,16 +31,19 @@ struct TypeAndValue {
// ExprInfo stores information used for "untyped" expressions // ExprInfo stores information used for "untyped" expressions
struct ExprInfo : TypeAndValue { struct ExprInfo {
AddressingMode mode;
Type * type;
ExactValue value;
bool is_lhs; // Debug info bool is_lhs; // Debug info
}; };
gb_inline ExprInfo make_expr_info(AddressingMode mode, Type *type, ExactValue value, bool is_lhs) { gb_inline ExprInfo make_expr_info(AddressingMode mode, Type *type, ExactValue value, bool is_lhs) {
ExprInfo ei = {}; ExprInfo ei = {};
ei.is_lhs = is_lhs;
ei.mode = mode; ei.mode = mode;
ei.type = type; ei.type = type;
ei.value = value; ei.value = value;
ei.is_lhs = is_lhs;
return ei; return ei;
} }
@@ -289,6 +292,7 @@ struct CheckerContext {
DeclInfo * curr_proc_decl; DeclInfo * curr_proc_decl;
Type * curr_proc_sig; Type * curr_proc_sig;
ForeignContext foreign_context; ForeignContext foreign_context;
gbAllocator allocator;
CheckerTypePath *type_path; CheckerTypePath *type_path;
isize type_level; // TODO(bill): Actually handle correctly isize type_level; // TODO(bill): Actually handle correctly
@@ -337,7 +341,7 @@ struct Checker {
gbAllocator allocator; gbAllocator allocator;
CheckerContext context; CheckerContext init_ctx;
bool done_preload; 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 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_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_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_entity_use (CheckerContext *c, AstNode *identifier, Entity *entity);
void add_implicit_entity (Checker *c, AstNode *node, Entity *e); void add_implicit_entity (CheckerContext *c, AstNode *node, Entity *e);
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);
void add_type_info_type (Checker *c, Type *t); 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_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); bool check_arity_match(CheckerContext *c, AstNodeValueDecl *vd, bool is_global = false);
void check_collect_entities(Checker *c, Array<AstNode *> nodes); void check_collect_entities(CheckerContext *c, Array<AstNode *> nodes);
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws); void check_collect_entities_from_when_stmt(CheckerContext *c, AstNodeWhenStmt *ws);
void check_delayed_file_import_entity(Checker *c, AstNode *decl); void check_delayed_file_import_entity(CheckerContext *c, AstNode *decl);
struct AttributeContext { struct AttributeContext {
String link_name; String link_name;
@@ -408,13 +412,13 @@ AttributeContext make_attribute_context(String link_prefix) {
return ac; 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); 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(); CheckerTypePath *new_checker_type_path();
void destroy_checker_type_path(CheckerTypePath *tp); void destroy_checker_type_path(CheckerTypePath *tp);
void check_type_path_push(Checker *c, Entity *e); void check_type_path_push(CheckerContext *c, Entity *e);
Entity *check_type_path_pop (Checker *c); Entity *check_type_path_pop (CheckerContext *c);
+8 -6
View File
@@ -3833,14 +3833,16 @@ String ir_mangle_name(irGen *s, Entity *e) {
return make_string(new_name, new_name_len-1); return make_string(new_name, new_name_len-1);
#else #else
GB_ASSERT(e->pkg != nullptr);
String pkg = e->pkg->name;
GB_ASSERT(!rune_is_digit(pkg[0]));
String name = e->token.string; 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); bool require_suffix_id = is_type_polymorphic(e->type);
if (require_suffix_id) { if (require_suffix_id) {
max_len += 21; 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); u8 *new_name = gb_alloc_array(a, u8, max_len);
isize new_name_len = gb_snprintf( isize new_name_len = gb_snprintf(
cast(char *)new_name, max_len, cast(char *)new_name, max_len,
"%.*s.%.*s", LIT(pkg), LIT(name) "%.*s.%.*s", LIT(pkgn), LIT(name)
); );
if (require_suffix_id) { if (require_suffix_id) {
char *str = cast(char *)new_name + new_name_len-1; char *str = cast(char *)new_name + new_name_len-1;