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