From 34a048f7daaf93b16ae4121bf5238f9008f3465b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Dec 2022 11:29:28 +0000 Subject: Replace compiler for loops for the hash-table types to simplify code usage --- src/check_expr.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9846199f8..fbc4f8b63 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -205,8 +205,8 @@ void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name); defer (did_you_mean_destroy(&d)); - for_array(i, set.entries) { - did_you_mean_append(&d, set.entries[i].value); + for (auto const &entry : set) { + did_you_mean_append(&d, entry.value); } check_did_you_mean_print(&d, prefix); } @@ -242,12 +242,10 @@ void check_did_you_mean_scope(String const &name, Scope *scope, char const *pref DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); defer (did_you_mean_destroy(&d)); - mutex_lock(&scope->mutex); - for_array(i, scope->elements.entries) { - Entity *e = scope->elements.entries[i].value; + MUTEX_GUARD_BLOCK(&scope->mutex) for (auto const &entry : scope->elements) { + Entity *e = entry.value; did_you_mean_append(&d, e->token.string); } - mutex_unlock(&scope->mutex); check_did_you_mean_print(&d, prefix); } @@ -322,8 +320,8 @@ void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reser check_collect_entities(c, nodes); - for_array(i, s->elements.entries) { - Entity *e = s->elements.entries[i].value; + for (auto const &entry : s->elements) { + Entity *e = entry.value; switch (e->kind) { case Entity_Constant: case Entity_TypeName: @@ -4918,8 +4916,8 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs if (e != nullptr) { DeclInfo *decl = decl_info_of_entity(e); if (decl != nullptr) { - for_array(k, decl->deps.entries) { - Entity *dep = decl->deps.entries[k].ptr; + for (auto const &entry : decl->deps) { + Entity *dep = entry.ptr; ptr_set_add(&c->decl->deps, dep); } } @@ -5671,8 +5669,7 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Slice *clauses, bool print_err) { if (clauses != nullptr) { - for_array(i, *clauses) { - Ast *clause = (*clauses)[i]; + for (Ast *clause : *clauses) { Operand o = {}; check_expr(ctx, &o, clause); if (o.mode != Addressing_Constant) { @@ -5693,8 +5690,8 @@ bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, S if (scope != nullptr) { isize print_count = 0; - for_array(j, scope->elements.entries) { - Entity *e = scope->elements.entries[j].value; + for (auto const &entry : scope->elements) { + Entity *e = entry.value; switch (e->kind) { case Entity_TypeName: { if (print_count == 0) error_line("\n\tWith the following definitions:\n"); -- cgit v1.2.3 From 690666537c8a27d3c418b38b3285899100c9a556 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 18 Dec 2022 21:46:27 +0000 Subject: Add `gb_internal` to checker --- src/check_builtin.cpp | 34 ++--- src/check_decl.cpp | 44 +++--- src/check_expr.cpp | 334 +++++++++++++++++++++--------------------- src/check_stmt.cpp | 46 +++--- src/check_type.cpp | 80 +++++----- src/checker.cpp | 393 +++++++++++++++++++++++++------------------------- src/types.cpp | 3 +- 7 files changed, 466 insertions(+), 468 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 533929200..859fbea28 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1,6 +1,6 @@ typedef bool (BuiltinTypeIsProc)(Type *t); -BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = { +gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = { nullptr, // BuiltinProc__type_simple_boolean_begin is_type_boolean, @@ -51,7 +51,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - }; -void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) { +gb_internal void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) { if (right_type == nullptr) { return; } @@ -62,7 +62,7 @@ void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, } } -void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { +gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { Type *left_type = nullptr; Type *right_type = nullptr; if (x->type->kind == Type_Tuple) { @@ -88,7 +88,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name } -void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) { +gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) { // TODO(bill): better error message gbString t = type_to_string(x.type); error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t); @@ -118,7 +118,7 @@ void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Op } -void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { +gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) { Type *left_type = nullptr; Type *right_type = nullptr; if (x->type->kind == Type_Tuple) { @@ -144,7 +144,7 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na } -bool does_require_msgSend_stret(Type *return_type) { +gb_internal bool does_require_msgSend_stret(Type *return_type) { if (return_type == nullptr) { return false; } @@ -165,7 +165,7 @@ bool does_require_msgSend_stret(Type *return_type) { return false; } -ObjcMsgKind get_objc_proc_kind(Type *return_type) { +gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) { if (return_type == nullptr) { return ObjcMsg_normal; } @@ -189,7 +189,7 @@ ObjcMsgKind get_objc_proc_kind(Type *return_type) { return ObjcMsg_normal; } -void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { +gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { ObjcMsgKind kind = get_objc_proc_kind(return_type); Scope *scope = create_scope(c->info, nullptr); @@ -230,7 +230,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Sliceproc); String builtin_name = bd->name.string; @@ -1170,7 +1170,7 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi } -bool is_valid_type_for_load(Type *type) { +gb_internal bool is_valid_type_for_load(Type *type) { if (type == t_invalid) { return false; } else if (is_type_string(type)) { @@ -1191,7 +1191,7 @@ bool is_valid_type_for_load(Type *type) { return false; } -LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { +gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -1256,7 +1256,7 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As } -bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { +gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -1581,7 +1581,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast return true; } -bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { +gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { error(call, "Inlining operators are not allowed on built-in procedures"); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 18e5477d6..a976c1b73 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1,7 +1,7 @@ -void check_stmt (CheckerContext *ctx, Ast *node, u32 flags); +gb_internal void check_stmt(CheckerContext *ctx, Ast *node, u32 flags); // NOTE(bill): 'content_name' is for debugging and error messages -Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) { +gb_internal 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) { @@ -110,7 +110,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri return e->type; } -void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice const &inits, String context_name) { +gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice const &inits, String context_name) { if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) { return; } @@ -144,7 +144,7 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl } } -void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { +gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { if (operand->mode == Addressing_Invalid || operand->type == t_invalid || e->type == t_invalid) { @@ -184,7 +184,7 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { } -bool is_type_distinct(Ast *node) { +gb_internal bool is_type_distinct(Ast *node) { for (;;) { if (node == nullptr) { return false; @@ -217,7 +217,7 @@ bool is_type_distinct(Ast *node) { return false; } -Ast *remove_type_alias_clutter(Ast *node) { +gb_internal Ast *remove_type_alias_clutter(Ast *node) { for (;;) { if (node == nullptr) { return nullptr; @@ -232,7 +232,7 @@ Ast *remove_type_alias_clutter(Ast *node) { } } -isize total_attribute_count(DeclInfo *decl) { +gb_internal isize total_attribute_count(DeclInfo *decl) { isize attribute_count = 0; for_array(i, decl->attributes) { Ast *attr = decl->attributes[i]; @@ -242,7 +242,7 @@ isize total_attribute_count(DeclInfo *decl) { return attribute_count; } -Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) { +gb_internal Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) { // NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations // // X :: enum {A, B, C} @@ -288,7 +288,7 @@ Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named return et; } -void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) { +gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) { GB_ASSERT(e->type == nullptr); DeclInfo *decl = decl_info_of_entity(e); @@ -390,7 +390,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) } -void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { +gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into // e.g. file entity inserted into its package scope String original_name = original_entity->token.string; @@ -433,7 +433,7 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { -void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) { +gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Constant); init = unparen_expr(init); @@ -609,12 +609,12 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, typedef bool TypeCheckSig(Type *t); -bool sig_compare(TypeCheckSig *a, Type *x, Type *y) { +gb_internal bool sig_compare(TypeCheckSig *a, Type *x, Type *y) { x = core_type(x); y = core_type(y); return (a(x) && a(y)); } -bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) { +gb_internal bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) { x = core_type(x); y = core_type(y); if (a == b) { @@ -623,7 +623,7 @@ bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) { return ((a(x) && b(y)) || (b(x) && a(y))); } -bool signature_parameter_similar_enough(Type *x, Type *y) { +gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) { if (sig_compare(is_type_pointer, x, y)) { return true; } @@ -674,7 +674,7 @@ bool signature_parameter_similar_enough(Type *x, Type *y) { } -bool are_signatures_similar_enough(Type *a_, Type *b_) { +gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) { GB_ASSERT(a_->kind == Type_Proc); GB_ASSERT(b_->kind == Type_Proc); TypeProc *a = &a_->Proc; @@ -704,7 +704,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) { return true; } -Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) { +gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) { Ast *ident = nullptr; Entity **foreign_library = nullptr; @@ -747,7 +747,7 @@ Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) { return nullptr; } -String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) { +gb_internal 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"); @@ -764,7 +764,7 @@ String handle_link_name(CheckerContext *ctx, Token token, String link_name, Stri return link_name; } -void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { +gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(e->type == nullptr); if (d->proc_lit->kind != Ast_ProcLit) { // TOOD(bill): Better error message @@ -1121,7 +1121,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) { +gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -1239,7 +1239,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); } -void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) { +gb_internal 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; @@ -1367,7 +1367,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) } -void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) { +gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) { if (e->state == EntityState_Resolved) { return; } @@ -1437,7 +1437,7 @@ struct ProcUsingVar { }; -void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { +gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { if (body == nullptr) { return; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fbc4f8b63..3003e07b6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -17,7 +17,7 @@ enum CallArgumentError { CallArgumentError_MAX, }; -char const *CallArgumentError_strings[CallArgumentError_MAX] = { +gb_global char const *CallArgumentError_strings[CallArgumentError_MAX] = { "None", "NoneProcedureType", "WrongTypes", @@ -57,7 +57,7 @@ struct ValidIndexAndScore { i64 score; }; -int valid_index_and_score_cmp(void const *a, void const *b) { +gb_internal int valid_index_and_score_cmp(void const *a, void const *b) { i64 si = (cast(ValidIndexAndScore const *)a)->score; i64 sj = (cast(ValidIndexAndScore const *)b)->score; return sj < si ? -1 : sj > si; @@ -70,56 +70,56 @@ typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); -void check_expr (CheckerContext *c, Operand *operand, Ast *expression); -void check_multi_expr (CheckerContext *c, Operand *operand, Ast *expression); -void check_multi_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression); -void check_multi_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *type_hint); -void check_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint); -ExprKind check_expr_base (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint); -void check_expr_with_type_hint (CheckerContext *c, Operand *o, Ast *e, Type *t); -Type * check_type (CheckerContext *c, Ast *expression); -Type * check_type_expr (CheckerContext *c, Ast *expression, Type *named_type); -Type * make_optional_ok_type (Type *value, bool typed=true); -Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint); -Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name); -Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure); -void check_not_tuple (CheckerContext *c, Operand *operand); -void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); -gbString expr_to_string (Ast *expression); -void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, Ast *body); -void update_untyped_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); -bool check_is_terminating (Ast *node, String const &label); -bool check_has_break (Ast *stmt, String const &label, bool implicit); -void check_stmt (CheckerContext *c, Ast *node, u32 flags); -void check_stmt_list (CheckerContext *c, Slice const &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, Ast *proc_type_node, Array *operands = nullptr); -void check_struct_type (CheckerContext *c, Type *struct_type, Ast *node, Array *poly_operands, - Type *named_type = nullptr, Type *original_type_for_poly = nullptr); -void check_union_type (CheckerContext *c, Type *union_type, Ast *node, Array *poly_operands, - Type *named_type = nullptr, Type *original_type_for_poly = nullptr); +gb_internal void check_expr (CheckerContext *c, Operand *operand, Ast *expression); +gb_internal void check_multi_expr (CheckerContext *c, Operand *operand, Ast *expression); +gb_internal void check_multi_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression); +gb_internal void check_multi_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *type_hint); +gb_internal void check_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint); +gb_internal ExprKind check_expr_base (CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint); +gb_internal void check_expr_with_type_hint (CheckerContext *c, Operand *o, Ast *e, Type *t); +gb_internal Type * check_type (CheckerContext *c, Ast *expression); +gb_internal Type * check_type_expr (CheckerContext *c, Ast *expression, Type *named_type); +gb_internal Type * make_optional_ok_type (Type *value, bool typed=true); +gb_internal Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint); +gb_internal Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name); +gb_internal Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure); +gb_internal void check_not_tuple (CheckerContext *c, Operand *operand); +gb_internal void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); +gb_internal gbString expr_to_string (Ast *expression); +gb_internal void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, Ast *body); +gb_internal void update_untyped_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); +gb_internal bool check_is_terminating (Ast *node, String const &label); +gb_internal bool check_has_break (Ast *stmt, String const &label, bool implicit); +gb_internal void check_stmt (CheckerContext *c, Ast *node, u32 flags); +gb_internal void check_stmt_list (CheckerContext *c, Slice const &stmts, u32 flags); +gb_internal void check_init_constant (CheckerContext *c, Entity *e, Operand *operand); +gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value); +gb_internal bool check_procedure_type (CheckerContext *c, Type *type, Ast *proc_type_node, Array *operands = nullptr); +gb_internal void check_struct_type (CheckerContext *c, Type *struct_type, Ast *node, Array *poly_operands, + Type *named_type = nullptr, Type *original_type_for_poly = nullptr); +gb_internal void check_union_type (CheckerContext *c, Type *union_type, Ast *node, Array *poly_operands, + Type *named_type = nullptr, Type *original_type_for_poly = nullptr); -CallArgumentData check_call_arguments (CheckerContext *c, Operand *operand, Type *proc_type, Ast *call); -Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name); +gb_internal CallArgumentData check_call_arguments (CheckerContext *c, Operand *operand, Type *proc_type, Ast *call); +gb_internal Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name); -void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); -void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); +gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); -Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); -Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); +gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); +gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); -bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint); +gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint); -void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_); +gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_); -void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type); -void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); -void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); -void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +gb_internal void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type); +gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); +gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); -bool is_diverging_expr(Ast *expr); +gb_internal bool is_diverging_expr(Ast *expr); enum LoadDirectiveResult { @@ -128,7 +128,7 @@ enum LoadDirectiveResult { LoadDirective_NotFound = 2, }; -bool is_load_directive_call(Ast *call) { +gb_internal bool is_load_directive_call(Ast *call) { call = unparen_expr(call); if (call->kind != Ast_CallExpr) { return false; @@ -141,9 +141,9 @@ bool is_load_directive_call(Ast *call) { String name = bd->name.string; return name == "load"; } -LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); +gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); -void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { +gb_internal void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); if (results.count != 0) { error_line("\tSuggestion: Did you mean?\n"); @@ -155,7 +155,7 @@ void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { } } -void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) { +gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) { if (e->kind != Entity_TypeName) { return; } @@ -189,7 +189,7 @@ void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_ } -void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") { +gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") { ERROR_BLOCK(); GB_ASSERT(e->kind == Entity_TypeName); GB_ASSERT(e->TypeName.objc_metadata != nullptr); @@ -211,7 +211,7 @@ void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, check_did_you_mean_print(&d, prefix); } -void check_did_you_mean_type(String const &name, Array const &fields, char const *prefix = "") { +gb_internal void check_did_you_mean_type(String const &name, Array const &fields, char const *prefix = "") { ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); @@ -224,7 +224,7 @@ void check_did_you_mean_type(String const &name, Array const &fields, } -void check_did_you_mean_type(String const &name, Slice const &fields, char const *prefix = "") { +gb_internal void check_did_you_mean_type(String const &name, Slice const &fields, char const *prefix = "") { ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); @@ -236,7 +236,7 @@ void check_did_you_mean_type(String const &name, Slice const &fields, check_did_you_mean_print(&d, prefix); } -void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") { +gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") { ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); @@ -249,7 +249,7 @@ void check_did_you_mean_scope(String const &name, Scope *scope, char const *pref check_did_you_mean_print(&d, prefix); } -Entity *entity_from_expr(Ast *expr) { +gb_internal Entity *entity_from_expr(Ast *expr) { expr = unparen_expr(expr); switch (expr->kind) { case Ast_Ident: @@ -260,7 +260,7 @@ Entity *entity_from_expr(Ast *expr) { return nullptr; } -void error_operand_not_expression(Operand *o) { +gb_internal void error_operand_not_expression(Operand *o) { if (o->mode == Addressing_Type) { gbString err = expr_to_string(o->expr); error(o->expr, "'%s' is not an expression but a type", err); @@ -269,7 +269,7 @@ void error_operand_not_expression(Operand *o) { } } -void error_operand_no_value(Operand *o) { +gb_internal void error_operand_no_value(Operand *o) { if (o->mode == Addressing_NoValue) { gbString err = expr_to_string(o->expr); Ast *x = unparen_expr(o->expr); @@ -283,7 +283,7 @@ void error_operand_no_value(Operand *o) { } } -void add_map_get_dependencies(CheckerContext *c) { +gb_internal void add_map_get_dependencies(CheckerContext *c) { if (build_context.use_static_map_calls) { add_package_dependency(c, "runtime", "map_desired_position"); add_package_dependency(c, "runtime", "map_probe_distance"); @@ -292,7 +292,7 @@ void add_map_get_dependencies(CheckerContext *c) { } } -void add_map_set_dependencies(CheckerContext *c) { +gb_internal void add_map_set_dependencies(CheckerContext *c) { init_core_source_code_location(c->checker); if (t_map_set_proc == nullptr) { @@ -308,14 +308,14 @@ void add_map_set_dependencies(CheckerContext *c) { } } -void add_map_reserve_dependencies(CheckerContext *c) { +gb_internal void add_map_reserve_dependencies(CheckerContext *c) { init_core_source_code_location(c->checker); add_package_dependency(c, "runtime", "__dynamic_map_reserve"); } -void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reserve_size) { +gb_internal void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reserve_size) { Scope *s = c->scope; check_collect_entities(c, nodes); @@ -337,8 +337,8 @@ void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reser } } -bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type, - Array *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { +gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type, + Array *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { /////////////////////////////////////////////////////////////////////////////// // // // TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! // @@ -571,24 +571,24 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_ return true; } -bool check_polymorphic_procedure_assignment(CheckerContext *c, Operand *operand, Type *type, Ast *poly_def_node, PolyProcData *poly_proc_data) { +gb_internal bool check_polymorphic_procedure_assignment(CheckerContext *c, Operand *operand, Type *type, Ast *poly_def_node, PolyProcData *poly_proc_data) { if (operand->expr == nullptr) return false; Entity *base_entity = entity_of_node(operand->expr); if (base_entity == nullptr) return false; return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_def_node, poly_proc_data); } -bool find_or_generate_polymorphic_procedure_from_parameters(CheckerContext *c, Entity *base_entity, Array *operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { +gb_internal bool find_or_generate_polymorphic_procedure_from_parameters(CheckerContext *c, Entity *base_entity, Array *operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { return find_or_generate_polymorphic_procedure(c, base_entity, nullptr, operands, poly_def_node, poly_proc_data); } -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); +gb_internal bool check_type_specialization_to(CheckerContext *c, Type *specialization, Type *type, bool compound, bool modify_type); +gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type); +gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type); #define MAXIMUM_TYPE_DISTANCE 10 -i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) { +gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) { if (c == nullptr) { GB_ASSERT(operand->mode == Addressing_Value); GB_ASSERT(is_type_typed(operand->type)); @@ -887,7 +887,7 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type } -i64 assign_score_function(i64 distance, bool is_variadic=false) { +gb_internal i64 assign_score_function(i64 distance, bool is_variadic=false) { // 3*x^2 + 1 > x^2 + x + 1 (for positive x) i64 const c = 3*MAXIMUM_TYPE_DISTANCE*MAXIMUM_TYPE_DISTANCE + 1; @@ -900,7 +900,7 @@ i64 assign_score_function(i64 distance, bool is_variadic=false) { } -bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false) { +gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false) { i64 score = 0; i64 distance = check_distance_between_types(c, operand, type); bool ok = distance >= 0; @@ -912,19 +912,19 @@ bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type } -bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) { +gb_internal 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); } -bool internal_check_is_assignable_to(Type *src, Type *dst) { +gb_internal bool internal_check_is_assignable_to(Type *src, Type *dst) { Operand x = {}; x.type = src; x.mode = Addressing_Value; return check_is_assignable_to(nullptr, &x, dst); } -AstPackage *get_package_of_type(Type *type) { +gb_internal AstPackage *get_package_of_type(Type *type) { for (;;) { if (type == nullptr) { return nullptr; @@ -962,7 +962,7 @@ AstPackage *get_package_of_type(Type *type) { // NOTE(bill): 'content_name' is for debugging and error messages -void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) { +gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *type, String context_name) { check_not_tuple(c, operand); if (operand->mode == Addressing_Invalid) { return; @@ -1110,7 +1110,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co } } -bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source_count) { +gb_internal bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source_count) { Type *gt = *gt_; GB_ASSERT(gt->kind == Type_Generic); @@ -1139,7 +1139,7 @@ bool polymorphic_assign_index(Type **gt_, i64 *dst_count, i64 source_count) { return false; } -bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type) { +gb_internal 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) { @@ -1439,7 +1439,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, return false; } -bool check_cycle(CheckerContext *c, Entity *curr, bool report) { +gb_internal bool check_cycle(CheckerContext *c, Entity *curr, bool report) { if (curr->state != EntityState_InProgress) { return false; } @@ -1461,7 +1461,7 @@ bool check_cycle(CheckerContext *c, Entity *curr, bool report) { return false; } -Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) { +gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) { GB_ASSERT(n->kind == Ast_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -1630,7 +1630,7 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ } -bool check_unary_op(CheckerContext *c, Operand *o, Token op) { +gb_internal 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); @@ -1672,7 +1672,7 @@ bool check_unary_op(CheckerContext *c, Operand *o, Token op) { return true; } -bool check_binary_op(CheckerContext *c, Operand *o, Token op) { +gb_internal bool check_binary_op(CheckerContext *c, Operand *o, Token op) { Type *main_type = o->type; // TODO(bill): Handle errors correctly @@ -1783,7 +1783,7 @@ bool check_binary_op(CheckerContext *c, Operand *o, Token op) { } -bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value) { +gb_internal 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; @@ -1998,7 +1998,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ } -void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2032,7 +2032,7 @@ void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type } } -void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2074,7 +2074,7 @@ void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type *type) { } -bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { +gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { GB_ASSERT(o->mode == Addressing_Constant); ExactValue out_value = o->value; if (is_type_constant_type(type) && check_representable_as_constant(ctx, o->value, type, &out_value)) { @@ -2112,7 +2112,7 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) { } } -bool check_is_not_addressable(CheckerContext *c, Operand *o) { +gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { if (o->mode == Addressing_OptionalOk) { Ast *expr = unselector_expr(o->expr); if (expr->kind != Ast_TypeAssertion) { @@ -2143,7 +2143,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) { return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } -void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { +gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { switch (op.kind) { case Token_And: { // Pointer address if (check_is_not_addressable(c, o)) { @@ -2270,7 +2270,7 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { o->mode = Addressing_Value; } -void add_comparison_procedures_for_fields(CheckerContext *c, Type *t) { +gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t) { if (t == nullptr) { return; } @@ -2323,7 +2323,7 @@ void add_comparison_procedures_for_fields(CheckerContext *c, Type *t) { } -void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { +gb_internal 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) { @@ -2516,7 +2516,7 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } -void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *type_hint) { +gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *type_hint) { GB_ASSERT(node->kind == Ast_BinaryExpr); ast_node(be, BinaryExpr, node); @@ -2635,7 +2635,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ -bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { +gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) { return true; } @@ -2851,7 +2851,7 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { return false; } -bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { +gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; Type *bt = base_type(type); @@ -2886,7 +2886,7 @@ bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { } -void check_cast(CheckerContext *c, Operand *x, Type *type) { +gb_internal 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; @@ -2930,7 +2930,7 @@ void check_cast(CheckerContext *c, Operand *x, Type *type) { x->type = type; } -bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) { +gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) { if (!is_operand_value(*o)) { error(o->expr, "'transmute' can only be applied to values"); o->mode = Addressing_Invalid; @@ -3043,7 +3043,7 @@ bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) { return true; } -bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y) { +gb_internal 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)) { @@ -3054,19 +3054,19 @@ bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y return false; } -bool is_ise_expr(Ast *node) { +gb_internal bool is_ise_expr(Ast *node) { node = unparen_expr(node); return node->kind == Ast_ImplicitSelectorExpr; } -bool can_use_other_type_as_type_hint(bool use_lhs_as_type_hint, Type *other_type) { +gb_internal bool can_use_other_type_as_type_hint(bool use_lhs_as_type_hint, Type *other_type) { if (use_lhs_as_type_hint) { // RHS in this case return other_type != nullptr && other_type != t_invalid && is_type_typed(other_type); } return false; } -Type *check_matrix_type_hint(Type *matrix, Type *type_hint) { +gb_internal Type *check_matrix_type_hint(Type *matrix, Type *type_hint) { Type *xt = base_type(matrix); if (type_hint != nullptr) { Type *th = base_type(type_hint); @@ -3086,7 +3086,7 @@ Type *check_matrix_type_hint(Type *matrix, Type *type_hint) { } -void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand *y, Type *type_hint, bool use_lhs_as_type_hint) { +gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand *y, Type *type_hint, bool use_lhs_as_type_hint) { if (!check_binary_op(c, x, op)) { x->mode = Addressing_Invalid; return; @@ -3197,7 +3197,7 @@ matrix_error: } -void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) { +gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) { GB_ASSERT(node->kind == Ast_BinaryExpr); Operand y_ = {}, *y = &y_; @@ -3563,7 +3563,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint x->mode = Addressing_Value; } -Operand make_operand_from_node(Ast *node) { +gb_internal Operand make_operand_from_node(Ast *node) { GB_ASSERT(node != nullptr); Operand x = {}; x.expr = node; @@ -3574,7 +3574,7 @@ Operand make_operand_from_node(Ast *node) { } -void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) { +gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) { GB_ASSERT(e != nullptr); ExprInfo *old = check_get_expr_info(c, e); if (old == nullptr) { @@ -3689,7 +3689,7 @@ void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) add_type_and_value(c->info, e, old->mode, type, old->value); } -void update_untyped_expr_value(CheckerContext *c, Ast *e, ExactValue value) { +gb_internal void update_untyped_expr_value(CheckerContext *c, Ast *e, ExactValue value) { GB_ASSERT(e != nullptr); ExprInfo *found = check_get_expr_info(c, e); if (found) { @@ -3697,7 +3697,7 @@ void update_untyped_expr_value(CheckerContext *c, Ast *e, ExactValue value) { } } -void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_type) { +gb_internal 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); gbString from_type_str = type_to_string(operand->type); @@ -3728,7 +3728,7 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ operand->mode = Addressing_Invalid; } -ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { +gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { Type *t = core_type(type); if (is_type_boolean(t)) { // v = exact_value_to_boolean(v); @@ -3746,7 +3746,7 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { return v; } -void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { +gb_internal 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 || @@ -3995,7 +3995,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { operand->type = target_type; } -bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { +gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { Operand operand = {Addressing_Invalid}; check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { @@ -4121,7 +4121,7 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast return true; } -ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 index, bool *success_, bool *finish_) { +gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 index, bool *success_, bool *finish_) { if (value.kind == ExactValue_String) { GB_ASSERT(0 <= index && index < value.value_string.len); u8 val = value.value_string[index]; @@ -4269,7 +4269,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in -ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selection sel, bool *success_) { +gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selection sel, bool *success_) { if (operand->mode != Addressing_Constant) { if (success_) *success_ = false; return empty_exact_value; @@ -4349,7 +4349,7 @@ ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selecti return empty_exact_value; } -Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize new_count) { +gb_internal Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize new_count) { Type *array_type = base_type(type_deref(original_type)); GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); if (array_type->kind == Type_SimdVector) { @@ -4376,7 +4376,7 @@ Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize n } -bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool *allow_builtin) { +gb_internal bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool *allow_builtin) { bool is_declared = entity != nullptr; if (is_declared) { if (entity->kind == Entity_Builtin) { @@ -4391,7 +4391,7 @@ bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool * } // NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning -Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool ident_only) { +gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool ident_only) { if (node->kind == Ast_Ident) { String name = node->Ident.token.string; return scope_lookup(c->scope, name); @@ -4471,7 +4471,7 @@ Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool i } -Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *type_hint) { +gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *type_hint) { ast_node(se, SelectorExpr, node); bool check_op_expr = true; @@ -4865,7 +4865,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ return entity; } -bool is_type_normal_pointer(Type *ptr, Type **elem) { +gb_internal bool is_type_normal_pointer(Type *ptr, Type **elem) { ptr = base_type(ptr); if (is_type_pointer(ptr)) { if (is_type_rawptr(ptr)) { @@ -4877,7 +4877,7 @@ bool is_type_normal_pointer(Type *ptr, Type **elem) { return false; } -bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) { +gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) { switch (node->kind) { case_ast_node(i, Ident, node); String name = i->token.string; @@ -4907,7 +4907,7 @@ bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **o return false; } -isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) { +gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) { if (lhs != nullptr && c->decl != nullptr) { mutex_lock(&c->info->deps_mutex); @@ -4930,7 +4930,7 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs } -bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { +gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -5011,7 +5011,7 @@ bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, -bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, bool allow_ok, bool is_variadic) { +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, bool allow_ok, bool is_variadic) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -5104,7 +5104,7 @@ bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, } -bool is_expr_constant_zero(Ast *expr) { +gb_internal bool is_expr_constant_zero(Ast *expr) { GB_ASSERT(expr != nullptr); auto v = exact_value_to_integer(expr->tav.value); if (v.kind == ExactValue_Integer) { @@ -5113,7 +5113,7 @@ bool is_expr_constant_zero(Ast *expr) { return false; } -isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_) { +gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_) { GB_ASSERT(pt != nullptr); GB_ASSERT(pt->kind == Type_Proc); isize param_count = 0; @@ -5167,7 +5167,7 @@ isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_ } -CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { +gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { ast_node(ce, CallExpr, call); GB_ASSERT(is_type_proc(proc_type)); proc_type = base_type(proc_type); @@ -5406,7 +5406,7 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { return err; } -bool is_call_expr_field_value(AstCallExpr *ce) { +gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { GB_ASSERT(ce != nullptr); if (ce->args.count == 0) { @@ -5415,7 +5415,7 @@ bool is_call_expr_field_value(AstCallExpr *ce) { return ce->args[0]->kind == Ast_FieldValue; } -isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { +gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { isize param_count = pt->param_count; for (isize i = 0; i < param_count; i++) { Entity *e = pt->params->Tuple.variables[i]; @@ -5429,7 +5429,7 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { } return -1; } -isize lookup_procedure_result(TypeProc *pt, String result_name) { +gb_internal isize lookup_procedure_result(TypeProc *pt, String result_name) { isize result_count = pt->result_count; for (isize i = 0; i < result_count; i++) { Entity *e = pt->results->Tuple.variables[i]; @@ -5444,7 +5444,7 @@ isize lookup_procedure_result(TypeProc *pt, String result_name) { return -1; } -CALL_ARGUMENT_CHECKER(check_named_call_arguments) { +gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { ast_node(ce, CallExpr, call); GB_ASSERT(is_type_proc(proc_type)); proc_type = base_type(proc_type); @@ -5628,7 +5628,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { return err; } -Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) { +gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) { Entity **lhs = nullptr; isize lhs_count = -1; @@ -5667,7 +5667,7 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize } -bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Slice *clauses, bool print_err) { +gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Slice *clauses, bool print_err) { if (clauses != nullptr) { for (Ast *clause : *clauses) { Operand o = {}; @@ -5733,7 +5733,7 @@ bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, S } -CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Slice const &args) { +gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Slice const &args) { ast_node(ce, CallExpr, call); CallArgumentCheckerType *call_checker = check_call_arguments_internal; @@ -6262,7 +6262,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type } -isize lookup_polymorphic_record_parameter(Type *t, String parameter_name) { +gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_name) { if (!is_type_polymorphic_record(t)) { return -1; } @@ -6285,7 +6285,7 @@ isize lookup_polymorphic_record_parameter(Type *t, String parameter_name) { } -CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) { +gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) { ast_node(ce, CallExpr, call); Type *original_type = operand->type; @@ -6605,7 +6605,7 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper -ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { +gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, proc); @@ -6880,7 +6880,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr } -void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) { +gb_internal void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) { check_expr_base(c, o, e, t); check_not_tuple(c, o); char const *err_str = nullptr; @@ -6905,7 +6905,7 @@ void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) { } } -bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, Type *original_type) { +gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, Type *original_type) { switch (t->kind) { case Type_Basic: if (t->Basic.kind == Basic_string) { @@ -7018,7 +7018,7 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count, return false; } -bool ternary_compare_types(Type *x, Type *y) { +gb_internal bool ternary_compare_types(Type *x, Type *y) { if (is_type_untyped_undef(x) && type_has_undef(y)) { return true; } else if (is_type_untyped_nil(x) && type_has_nil(y)) { @@ -7032,7 +7032,7 @@ bool ternary_compare_types(Type *x, Type *y) { } -bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { +gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { if (!is_ast_range(node)) { return false; } @@ -7124,7 +7124,7 @@ bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValu return true; } -bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) { +gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) { if (is_operand_nil(*o)) { return true; } @@ -7143,7 +7143,7 @@ bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) { } -bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, AstImplicitSelectorExpr *ise, Type *th) { +gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, AstImplicitSelectorExpr *ise, Type *th) { if (is_type_enum(th)) { Type *enum_type = base_type(th); GB_ASSERT(enum_type->kind == Type_Enum); @@ -7182,7 +7182,7 @@ bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, AstImplicitSe return false; } -ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(ise, ImplicitSelectorExpr, node); o->type = t_invalid; @@ -7226,7 +7226,7 @@ ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, Ast *node, } -void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_) { +gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_) { switch (x->mode) { case Addressing_MapIndex: case Addressing_OptionalOk: @@ -7263,7 +7263,7 @@ void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, } -void check_matrix_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal void check_matrix_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(ie, MatrixIndexExpr, node); check_expr(c, o, ie->expr); @@ -7336,7 +7336,7 @@ struct TypeAndToken { typedef PtrMap SeenMap; -void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Operand operand, bool use_expr = true) { +gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Operand operand, bool use_expr = true) { if (operand.mode != Addressing_Constant) { return; } @@ -7378,7 +7378,7 @@ void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Operand operan } -void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Operand const &x, Operand const &lhs, Operand const &rhs) { +gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Operand const &x, Operand const &lhs, Operand const &rhs) { if (is_type_enum(x.type)) { // TODO(bill): Fix this logic so it's fast!!! @@ -7419,11 +7419,11 @@ void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Ope } } } -void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { +gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { add_constant_switch_case(ctx, seen, x); } -ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(bd, BasicDirective, node); ExprKind kind = Expr_Expr; @@ -7477,7 +7477,7 @@ ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, Ast *node, Ty return kind; } -ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; Operand cond = {Addressing_Invalid}; ast_node(te, TernaryIfExpr, node); @@ -7555,7 +7555,7 @@ ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *t return kind; } -ExprKind check_ternary_when_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_ternary_when_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; Operand cond = {}; ast_node(te, TernaryWhenExpr, node); @@ -7582,7 +7582,7 @@ ExprKind check_ternary_when_expr(CheckerContext *c, Operand *o, Ast *node, Type return kind; } -ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(oe, OrElseExpr, node); String name = oe->token.string; @@ -7696,7 +7696,7 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type return Expr_Expr; } -ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(re, OrReturnExpr, node); String name = re->token.string; @@ -7775,7 +7775,7 @@ ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *node, Type *ty return Expr_Expr; } -ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -8739,7 +8739,7 @@ ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type * return kind; } -ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(ta, TypeAssertion, node); check_expr(c, o, ta->expr); @@ -8868,7 +8868,7 @@ ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *node, Type *ty return kind; } -ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(se, SelectorCallExpr, node); // IMPORTANT NOTE(bill, 2020-05-22): This is a complete hack to get a shorthand which is extremely useful for vtables // COM APIs is a great example of where this kind of thing is extremely useful @@ -9016,7 +9016,7 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type } -ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(ie, IndexExpr, node); check_expr(c, o, ie->expr); @@ -9140,7 +9140,7 @@ ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_h return kind; } -ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Stmt; ast_node(se, SliceExpr, node); check_expr(c, o, se->expr); @@ -9328,7 +9328,7 @@ ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_h return kind; } -ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { u32 prev_state_flags = c->state_flags; defer (c->state_flags = prev_state_flags); if (node->state_flags != 0) { @@ -9755,7 +9755,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type -ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { +gb_internal ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = check_expr_base_internal(c, o, node, type_hint); if (o->type != nullptr && core_type(o->type) == nullptr) { o->type = t_invalid; @@ -9777,7 +9777,7 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi } -void check_multi_expr_or_type(CheckerContext *c, Operand *o, Ast *e) { +gb_internal void check_multi_expr_or_type(CheckerContext *c, Operand *o, Ast *e) { check_expr_base(c, o, e, nullptr); switch (o->mode) { default: @@ -9789,7 +9789,7 @@ void check_multi_expr_or_type(CheckerContext *c, Operand *o, Ast *e) { o->mode = Addressing_Invalid; } -void check_multi_expr(CheckerContext *c, Operand *o, Ast *e) { +gb_internal void check_multi_expr(CheckerContext *c, Operand *o, Ast *e) { check_expr_base(c, o, e, nullptr); switch (o->mode) { default: @@ -9804,7 +9804,7 @@ void check_multi_expr(CheckerContext *c, Operand *o, Ast *e) { o->mode = Addressing_Invalid; } -void check_multi_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { +gb_internal void check_multi_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { check_expr_base(c, o, e, type_hint); switch (o->mode) { default: @@ -9819,7 +9819,7 @@ void check_multi_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type o->mode = Addressing_Invalid; } -void check_not_tuple(CheckerContext *c, Operand *o) { +gb_internal 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) { @@ -9832,13 +9832,13 @@ void check_not_tuple(CheckerContext *c, Operand *o) { } } -void check_expr(CheckerContext *c, Operand *o, Ast *e) { +gb_internal void check_expr(CheckerContext *c, Operand *o, Ast *e) { check_multi_expr(c, o, e); check_not_tuple(c, o); } -void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { +gb_internal void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { check_expr_base(c, o, e, type_hint); check_not_tuple(c, o); error_operand_no_value(o); @@ -9846,7 +9846,7 @@ void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) -bool is_exact_value_zero(ExactValue const &v) { +gb_internal bool is_exact_value_zero(ExactValue const &v) { switch (v.kind) { case ExactValue_Invalid: return true; @@ -9910,9 +9910,9 @@ bool is_exact_value_zero(ExactValue const &v) { -gbString write_expr_to_string(gbString str, Ast *node, bool shorthand); +gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthand); -gbString write_struct_fields_to_string(gbString str, Slice const ¶ms) { +gb_internal gbString write_struct_fields_to_string(gbString str, Slice const ¶ms) { for_array(i, params) { if (i > 0) { str = gb_string_appendc(str, ", "); @@ -9922,7 +9922,7 @@ gbString write_struct_fields_to_string(gbString str, Slice const ¶ms) return str; } -gbString string_append_string(gbString str, String string) { +gb_internal gbString string_append_string(gbString str, String string) { if (string.len > 0) { return gb_string_append_length(str, &string[0], string.len); } @@ -9930,13 +9930,13 @@ gbString string_append_string(gbString str, String string) { } -gbString string_append_token(gbString str, Token token) { +gb_internal gbString string_append_token(gbString str, Token token) { str = string_append_string(str, token.string); return str; } -gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { +gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { if (node == nullptr) return str; @@ -10501,9 +10501,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { return str; } -gbString expr_to_string(Ast *expression) { +gb_internal gbString expr_to_string(Ast *expression) { return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, false); } -gbString expr_to_string_shorthand(Ast *expression) { +gb_internal gbString expr_to_string_shorthand(Ast *expression) { return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, true); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 3fe6699ea..cae9c3537 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1,4 +1,4 @@ -bool is_diverging_expr(Ast *expr) { +gb_internal bool is_diverging_expr(Ast *expr) { expr = unparen_expr(expr); if (expr->kind != Ast_CallExpr) { return false; @@ -23,14 +23,14 @@ bool is_diverging_expr(Ast *expr) { t = base_type(t); return t != nullptr && t->kind == Type_Proc && t->Proc.diverging; } -bool is_diverging_stmt(Ast *stmt) { +gb_internal bool is_diverging_stmt(Ast *stmt) { if (stmt->kind != Ast_ExprStmt) { return false; } return is_diverging_expr(stmt->ExprStmt.expr); } -bool contains_deferred_call(Ast *node) { +gb_internal bool contains_deferred_call(Ast *node) { if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { return true; } @@ -61,7 +61,7 @@ bool contains_deferred_call(Ast *node) { return false; } -void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) { +gb_internal void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) { if (stmts.count == 0) { return; } @@ -137,7 +137,7 @@ void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) } } -bool check_is_terminating_list(Slice const &stmts, String const &label) { +gb_internal bool check_is_terminating_list(Slice const &stmts, String const &label) { // Iterate backwards for (isize n = stmts.count-1; n >= 0; n--) { Ast *stmt = stmts[n]; @@ -155,7 +155,7 @@ bool check_is_terminating_list(Slice const &stmts, String const &label) { return false; } -bool check_has_break_list(Slice const &stmts, String const &label, bool implicit) { +gb_internal bool check_has_break_list(Slice const &stmts, String const &label, bool implicit) { for_array(i, stmts) { Ast *stmt = stmts[i]; if (check_has_break(stmt, label, implicit)) { @@ -166,7 +166,7 @@ bool check_has_break_list(Slice const &stmts, String const &label, bool i } -bool check_has_break(Ast *stmt, String const &label, bool implicit) { +gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit) { switch (stmt->kind) { case Ast_BranchStmt: if (stmt->BranchStmt.token.kind == Token_break) { @@ -225,7 +225,7 @@ bool check_has_break(Ast *stmt, String const &label, bool implicit) { // NOTE(bill): The last expression has to be a 'return' statement // TODO(bill): This is a mild hack and should be probably handled properly -bool check_is_terminating(Ast *node, String const &label) { +gb_internal bool check_is_terminating(Ast *node, String const &label) { switch (node->kind) { case_ast_node(rs, ReturnStmt, node); return true; @@ -327,7 +327,7 @@ bool check_is_terminating(Ast *node, String const &label) { -Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { +gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { if (rhs->mode == Addressing_Invalid) { return nullptr; } @@ -477,8 +477,8 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) } -void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags); -void check_stmt(CheckerContext *ctx, Ast *node, u32 flags) { +gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags); +gb_internal void check_stmt(CheckerContext *ctx, Ast *node, u32 flags) { u32 prev_state_flags = ctx->state_flags; if (node->state_flags != 0) { @@ -510,7 +510,7 @@ void check_stmt(CheckerContext *ctx, Ast *node, u32 flags) { } -void check_when_stmt(CheckerContext *ctx, AstWhenStmt *ws, u32 flags) { +gb_internal void check_when_stmt(CheckerContext *ctx, AstWhenStmt *ws, u32 flags) { Operand operand = {Addressing_Invalid}; check_expr(ctx, &operand, ws->cond); if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) { @@ -539,7 +539,7 @@ void check_when_stmt(CheckerContext *ctx, AstWhenStmt *ws, u32 flags) { } } -void check_label(CheckerContext *ctx, Ast *label, Ast *parent) { +gb_internal void check_label(CheckerContext *ctx, Ast *label, Ast *parent) { if (label == nullptr) { return; } @@ -582,7 +582,7 @@ void check_label(CheckerContext *ctx, Ast *label, Ast *parent) { } // Returns 'true' for 'continue', 'false' for 'return' -bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) { +gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, bool is_selector, Entity *e) { if (e == nullptr) { if (is_blank_ident(expr)) { error(us->token, "'using' in a statement is not allowed with the blank identifier '_'"); @@ -704,7 +704,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b return true; } -void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { +gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(irs, UnrollRangeStmt, node); check_open_scope(ctx, node); @@ -863,7 +863,7 @@ void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } -void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { +gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(ss, SwitchStmt, node); Operand x = {}; @@ -1092,7 +1092,7 @@ enum TypeSwitchKind { TypeSwitch_Any, }; -TypeSwitchKind check_valid_type_switch_type(Type *type) { +gb_internal TypeSwitchKind check_valid_type_switch_type(Type *type) { type = type_deref(type); if (is_type_union(type)) { return TypeSwitch_Union; @@ -1103,7 +1103,7 @@ TypeSwitchKind check_valid_type_switch_type(Type *type) { return TypeSwitch_Invalid; } -void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { +gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(ss, TypeSwitchStmt, node); Operand x = {}; @@ -1318,7 +1318,7 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { } } -void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { +gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { if (body->kind != Ast_BlockStmt) { return; } @@ -1377,7 +1377,7 @@ void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { } } -bool all_operands_valid(Array const &operands) { +gb_internal bool all_operands_valid(Array const &operands) { if (any_errors()) { for_array(i, operands) { if (operands[i].type == t_invalid) { @@ -1388,7 +1388,7 @@ bool all_operands_valid(Array const &operands) { return true; } -bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) { +gb_internal bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) { BuiltinProcId id = BuiltinProc_Invalid; Entity *e = entity_of_node(expr); if (e != nullptr && e->kind == Entity_Builtin) { @@ -1400,7 +1400,7 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) { return id != BuiltinProc_Invalid; } -bool check_expr_is_stack_variable(Ast *expr) { +gb_internal bool check_expr_is_stack_variable(Ast *expr) { /* expr = unparen_expr(expr); Entity *e = entity_of_node(expr); @@ -1419,7 +1419,7 @@ bool check_expr_is_stack_variable(Ast *expr) { return false; } -void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { +gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { case_ast_node(_, EmptyStmt, node); case_end; diff --git a/src/check_type.cpp b/src/check_type.cpp index 62ca19c57..4634e1fbe 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1,6 +1,6 @@ -ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location); +gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location); -void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { +gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { t = base_type(t); GB_ASSERT(t->kind == Type_Array); Entity *e = scope_lookup_current(ctx->scope, name); @@ -27,7 +27,7 @@ void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, } } -void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) { +gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) { if (t == nullptr) { return; } @@ -81,7 +81,7 @@ void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field } } -bool does_field_type_allow_using(Type *t) { +gb_internal bool does_field_type_allow_using(Type *t) { t = base_type(t); if (is_type_struct(t)) { return true; @@ -91,8 +91,8 @@ bool does_field_type_allow_using(Type *t) { return false; } -void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields, String **tags, Slice const ¶ms, - isize init_field_capacity, Type *struct_type, String context) { +gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields, String **tags, Slice const ¶ms, + isize init_field_capacity, Type *struct_type, String context) { auto fields_array = array_make(heap_allocator(), 0, init_field_capacity); auto tags_array = array_make(heap_allocator(), 0, init_field_capacity); @@ -219,7 +219,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice *fields } -bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) { +gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) { GB_ASSERT(align_ != nullptr); Operand o = {}; check_expr(ctx, &o, node); @@ -256,7 +256,7 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) { } -Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure) { +gb_internal Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure) { mutex_lock(&ctx->info->gen_types_mutex); defer (mutex_unlock(&ctx->info->gen_types_mutex)); @@ -320,7 +320,7 @@ Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, } -void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) { +gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) { GB_ASSERT(is_type_named(named_type)); gbAllocator a = heap_allocator(); Scope *s = ctx->scope->parent; @@ -358,10 +358,10 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t mutex_unlock(&ctx->info->gen_types_mutex); } -Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params, - bool *is_polymorphic_, - Ast *node, Array *poly_operands, - Type *named_type, Type *original_type_for_poly) { +gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params, + bool *is_polymorphic_, + Ast *node, Array *poly_operands, + Type *named_type, Type *original_type_for_poly) { Type *polymorphic_params_type = nullptr; bool can_check_fields = true; GB_ASSERT(is_polymorphic_ != nullptr); @@ -540,7 +540,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para return polymorphic_params_type; } -bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array *poly_operands, bool *is_polymorphic_) { +gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array *poly_operands, bool *is_polymorphic_) { if (poly_operands == nullptr) { return false; } @@ -569,7 +569,7 @@ bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_ } -void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array *poly_operands, Type *named_type, Type *original_type_for_poly) { +gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array *poly_operands, Type *named_type, Type *original_type_for_poly) { GB_ASSERT(is_type_struct(struct_type)); ast_node(st, StructType, node); @@ -626,7 +626,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< } } } -void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array *poly_operands, Type *named_type, Type *original_type_for_poly) { +gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array *poly_operands, Type *named_type, Type *original_type_for_poly) { GB_ASSERT(is_type_union(union_type)); ast_node(ut, UnionType, node); @@ -709,7 +709,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayEnum.max_value_index = max_value_index; } -bool is_type_valid_bit_set_range(Type *t) { +gb_internal bool is_type_valid_bit_set_range(Type *t) { if (is_type_integer(t)) { return true; } @@ -861,7 +861,7 @@ bool is_type_valid_bit_set_range(Type *t) { return false; } -void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) { +gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) { ast_node(bs, BitSetType, node); GB_ASSERT(type->kind == Type_BitSet); type->BitSet.node = node; @@ -1102,7 +1102,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no } -bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) { +gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) { if (type == nullptr || type == t_invalid) { return true; @@ -1229,7 +1229,7 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ } -Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) { +gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) { bool modify_type = !ctx->no_polymorphic_errors; bool show_error = modify_type && !ctx->hide_polymorphic_errors; if (!is_operand_value(operand)) { @@ -1256,7 +1256,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper return t_invalid; } -bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { +gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { if (expr == nullptr) { return false; } @@ -1275,7 +1275,7 @@ bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { } -ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) { +gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) { ParameterValue param_value = {}; param_value.original_ast_expr = expr; if (expr == nullptr) { @@ -1370,7 +1370,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type * } -Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array *operands) { +gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array *operands) { if (_params == nullptr) { return nullptr; } @@ -1814,7 +1814,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is return tuple; } -Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { +gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { if (_results == nullptr) { return nullptr; } @@ -1928,7 +1928,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { // NOTE(bill): 'operands' is for generating non generic procedure type -bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array *operands) { +gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array *operands) { ast_node(pt, ProcType, proc_type_node); if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) { @@ -2084,7 +2084,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, } -i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { +gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { if (e == nullptr) { return 0; } @@ -2169,7 +2169,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) { return 0; } -Type *make_optional_ok_type(Type *value, bool typed) { +gb_internal Type *make_optional_ok_type(Type *value, bool typed) { gbAllocator a = permanent_allocator(); Type *t = alloc_type_tuple(); slice_init(&t->Tuple.variables, a, 2); @@ -2185,7 +2185,7 @@ enum : i64 { MAP_CACHE_LINE_SIZE = 1 << MAP_CACHE_LINE_LOG2 }; GB_STATIC_ASSERT(MAP_CACHE_LINE_SIZE >= 64); -void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) { +gb_internal void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) { i64 elem_sz = type_size_of(type); i64 len = 1; @@ -2197,7 +2197,7 @@ void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) { if (len_) *len_ = len; } -void init_map_internal_types(Type *type) { +gb_internal void init_map_internal_types(Type *type) { GB_ASSERT(type->kind == Type_Map); GB_ASSERT(t_allocator != nullptr); if (type->Map.lookup_result_type != nullptr) return; @@ -2210,7 +2210,7 @@ void init_map_internal_types(Type *type) { type->Map.lookup_result_type = make_optional_ok_type(value); } -void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { +gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { key = core_type(key); if (is_type_cstring(key)) { @@ -2249,7 +2249,7 @@ void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { } } -void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { +gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { GB_ASSERT(type->kind == Type_Map); ast_node(mt, MapType, node); @@ -2282,7 +2282,7 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { // error(node, "'map' types are not yet implemented"); } -void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) { +gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) { ast_node(mt, MatrixType, node); Operand row = {}; @@ -2346,7 +2346,7 @@ type_assign:; -Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) { +gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) { Type *bt_elem = base_type(elem); bool is_polymorphic = is_type_polymorphic(elem); @@ -2501,20 +2501,20 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el } -Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) { +gb_internal Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) { return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, count, generic_type, StructSoa_Fixed); } -Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) { +gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) { return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Slice); } -Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) { +gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) { return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Dynamic); } -bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { +gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { GB_ASSERT_NOT_NULL(type); if (e == nullptr) { *type = t_invalid; @@ -2997,7 +2997,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t return false; } -Type *check_type(CheckerContext *ctx, Ast *e) { +gb_internal Type *check_type(CheckerContext *ctx, Ast *e) { CheckerContext c = *ctx; c.type_path = new_checker_type_path(); defer (destroy_checker_type_path(c.type_path)); @@ -3005,7 +3005,7 @@ Type *check_type(CheckerContext *ctx, Ast *e) { return check_type_expr(&c, e, nullptr); } -Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) { +gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) { Type *type = nullptr; bool ok = check_type_internal(ctx, e, &type, named_type); diff --git a/src/checker.cpp b/src/checker.cpp index d5222f615..e2c430dc2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1,12 +1,12 @@ #include "entity.cpp" #include "types.cpp" -void check_expr(CheckerContext *c, Operand *operand, Ast *expression); -void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); -void add_comparison_procedures_for_fields(CheckerContext *c, Type *t); -Type *check_type(CheckerContext *ctx, Ast *e); +gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression); +gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr); +gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t); +gb_internal Type *check_type(CheckerContext *ctx, Ast *e); -bool is_operand_value(Operand o) { +gb_internal bool is_operand_value(Operand o) { switch (o.mode) { case Addressing_Value: case Addressing_Context: @@ -22,14 +22,14 @@ bool is_operand_value(Operand o) { } return false; } -bool is_operand_nil(Operand o) { +gb_internal bool is_operand_nil(Operand o) { return o.mode == Addressing_Value && o.type == t_untyped_nil; } -bool is_operand_undef(Operand o) { +gb_internal bool is_operand_undef(Operand o) { return o.mode == Addressing_Value && o.type == t_untyped_undef; } -bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { +gb_internal bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) { if (build_context.disallow_rtti && type) { if (is_type_any(type)) { gbString t = type_to_string(type); @@ -41,12 +41,12 @@ bool check_rtti_type_disallowed(Token const &token, Type *type, char const *form return false; } -bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) { +gb_internal bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) { GB_ASSERT(expr != nullptr); return check_rtti_type_disallowed(ast_token(expr), type, format); } -void scope_reset(Scope *scope) { +gb_internal void scope_reset(Scope *scope) { if (scope == nullptr) return; scope->head_child.store(nullptr, std::memory_order_relaxed); @@ -54,14 +54,14 @@ void scope_reset(Scope *scope) { ptr_set_clear(&scope->imported); } -void scope_reserve(Scope *scope, isize capacity) { +gb_internal void scope_reserve(Scope *scope, isize capacity) { isize cap = 2*capacity; if (cap > scope->elements.hashes.count) { string_map_rehash(&scope->elements, capacity); } } -i32 is_scope_an_ancestor(Scope *parent, Scope *child) { +gb_internal i32 is_scope_an_ancestor(Scope *parent, Scope *child) { i32 i = 0; while (child != nullptr) { if (parent == child) { @@ -73,35 +73,35 @@ i32 is_scope_an_ancestor(Scope *parent, Scope *child) { return -1; } -void entity_graph_node_set_destroy(EntityGraphNodeSet *s) { +gb_internal void entity_graph_node_set_destroy(EntityGraphNodeSet *s) { if (s->hashes.data != nullptr) { ptr_set_destroy(s); } } -void entity_graph_node_set_add(EntityGraphNodeSet *s, EntityGraphNode *n) { +gb_internal void entity_graph_node_set_add(EntityGraphNodeSet *s, EntityGraphNode *n) { if (s->hashes.data == nullptr) { ptr_set_init(s, heap_allocator()); } ptr_set_add(s, n); } -bool entity_graph_node_set_exists(EntityGraphNodeSet *s, EntityGraphNode *n) { +gb_internal bool entity_graph_node_set_exists(EntityGraphNodeSet *s, EntityGraphNode *n) { return ptr_set_exists(s, n); } -void entity_graph_node_set_remove(EntityGraphNodeSet *s, EntityGraphNode *n) { +gb_internal void entity_graph_node_set_remove(EntityGraphNodeSet *s, EntityGraphNode *n) { ptr_set_remove(s, n); } -void entity_graph_node_destroy(EntityGraphNode *n, gbAllocator a) { +gb_internal void entity_graph_node_destroy(EntityGraphNode *n, gbAllocator a) { entity_graph_node_set_destroy(&n->pred); entity_graph_node_set_destroy(&n->succ); gb_free(a, n); } -int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) { +gb_internal int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) { EntityGraphNode *x = data[i]; EntityGraphNode *y = data[j]; u64 a = x->entity->order_in_src; @@ -115,7 +115,7 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) { return +1; } -void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { +gb_internal void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { EntityGraphNode *x = data[i]; EntityGraphNode *y = data[j]; data[i] = y; @@ -126,42 +126,42 @@ void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { -void import_graph_node_set_destroy(ImportGraphNodeSet *s) { +gb_internal void import_graph_node_set_destroy(ImportGraphNodeSet *s) { if (s->hashes.data != nullptr) { ptr_set_destroy(s); } } -void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNode *n) { +gb_internal void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNode *n) { if (s->hashes.data == nullptr) { ptr_set_init(s, heap_allocator()); } ptr_set_add(s, n); } -bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) { +gb_internal bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) { return ptr_set_exists(s, n); } -void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) { +gb_internal void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) { ptr_set_remove(s, n); } -ImportGraphNode *import_graph_node_create(gbAllocator a, AstPackage *pkg) { +gb_internal ImportGraphNode *import_graph_node_create(gbAllocator a, AstPackage *pkg) { ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode); n->pkg = pkg; n->scope = pkg->scope; return n; } -void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) { +gb_internal void import_graph_node_destroy(ImportGraphNode *n, gbAllocator a) { import_graph_node_set_destroy(&n->pred); import_graph_node_set_destroy(&n->succ); gb_free(a, n); } -int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) { +gb_internal int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) { ImportGraphNode *x = data[i]; ImportGraphNode *y = data[j]; GB_ASSERT(x != y); @@ -177,7 +177,7 @@ int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) { return 0; } -void import_graph_node_swap(ImportGraphNode **data, isize i, isize j) { +gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j) { ImportGraphNode *x = data[i]; ImportGraphNode *y = data[j]; data[i] = y; @@ -186,7 +186,7 @@ void import_graph_node_swap(ImportGraphNode **data, isize i, isize j) { y->index = i; } -GB_COMPARE_PROC(ast_node_cmp) { +gb_internal GB_COMPARE_PROC(ast_node_cmp) { Ast *x = *cast(Ast **)a; Ast *y = *cast(Ast **)b; Token i = ast_token(x); @@ -199,7 +199,7 @@ GB_COMPARE_PROC(ast_node_cmp) { -void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { +gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { d->parent = parent; d->scope = scope; ptr_set_init(&d->deps, heap_allocator()); @@ -207,18 +207,18 @@ void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { array_init (&d->labels, heap_allocator()); } -DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { +gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { DeclInfo *d = gb_alloc_item(permanent_allocator(), DeclInfo); init_decl_info(d, scope, parent); return d; } -void destroy_declaration_info(DeclInfo *d) { +gb_internal void destroy_declaration_info(DeclInfo *d) { ptr_set_destroy(&d->deps); array_free(&d->labels); } -bool decl_info_has_init(DeclInfo *d) { +gb_internal bool decl_info_has_init(DeclInfo *d) { if (d->init_expr != nullptr) { return true; } @@ -239,7 +239,7 @@ bool decl_info_has_init(DeclInfo *d) { -Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { +gb_internal Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; string_map_init(&s->elements, heap_allocator(), init_elements_capacity); @@ -260,7 +260,7 @@ Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capaci return s; } -Scope *create_scope_from_file(CheckerInfo *info, AstFile *f) { +gb_internal Scope *create_scope_from_file(CheckerInfo *info, AstFile *f) { GB_ASSERT(f != nullptr); GB_ASSERT(f->pkg != nullptr); GB_ASSERT(f->pkg->scope != nullptr); @@ -276,7 +276,7 @@ Scope *create_scope_from_file(CheckerInfo *info, AstFile *f) { return s; } -Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) { +gb_internal Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) { GB_ASSERT(pkg != nullptr); isize total_pkg_decl_count = 0; @@ -307,7 +307,7 @@ Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) { return s; } -void destroy_scope(Scope *scope) { +gb_internal void destroy_scope(Scope *scope) { for (auto const &entry : scope->elements) { Entity *e = entry.value; if (e->kind == Entity_Variable) { @@ -331,7 +331,7 @@ void destroy_scope(Scope *scope) { } -void add_scope(CheckerContext *c, Ast *node, Scope *scope) { +gb_internal void add_scope(CheckerContext *c, Ast *node, Scope *scope) { GB_ASSERT(node != nullptr); GB_ASSERT(scope != nullptr); scope->node = node; @@ -352,7 +352,7 @@ void add_scope(CheckerContext *c, Ast *node, Scope *scope) { } } -Scope *scope_of_node(Ast *node) { +gb_internal Scope *scope_of_node(Ast *node) { if (node == nullptr) { return nullptr; } @@ -375,7 +375,7 @@ Scope *scope_of_node(Ast *node) { } -void check_open_scope(CheckerContext *c, Ast *node) { +gb_internal void check_open_scope(CheckerContext *c, Ast *node) { node = unparen_expr(node); GB_ASSERT(node->kind == Ast_Invalid || is_ast_stmt(node) || @@ -397,12 +397,12 @@ void check_open_scope(CheckerContext *c, Ast *node) { c->state_flags |= StateFlag_bounds_check; } -void check_close_scope(CheckerContext *c) { +gb_internal void check_close_scope(CheckerContext *c) { c->scope = c->scope->parent; } -Entity *scope_lookup_current(Scope *s, String const &name) { +gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { Entity **found = string_map_get(&s->elements, name); if (found) { return *found; @@ -410,7 +410,7 @@ Entity *scope_lookup_current(Scope *s, String const &name) { return nullptr; } -void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) { +gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) { if (scope != nullptr) { bool gone_thru_proc = false; bool gone_thru_package = false; @@ -455,7 +455,7 @@ void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entit if (scope_) *scope_ = nullptr; } -Entity *scope_lookup(Scope *s, String const &name) { +gb_internal Entity *scope_lookup(Scope *s, String const &name) { Entity *entity = nullptr; scope_lookup_parent(s, name, nullptr, &entity); return entity; @@ -463,7 +463,7 @@ Entity *scope_lookup(Scope *s, String const &name) { -Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity, bool use_mutex=true) { +gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity, bool use_mutex=true) { if (name == "") { return nullptr; } @@ -502,7 +502,7 @@ end:; return result; } -Entity *scope_insert(Scope *s, Entity *entity, bool use_mutex) { +gb_internal Entity *scope_insert(Scope *s, Entity *entity, bool use_mutex) { String name = entity->token.string; return scope_insert_with_name(s, name, entity, use_mutex); } @@ -528,14 +528,14 @@ struct VettedEntity { Entity *entity; Entity *other; }; -void init_vetted_entity(VettedEntity *ve, VettedEntityKind kind, Entity *entity, Entity *other=nullptr) { +gb_internal void init_vetted_entity(VettedEntity *ve, VettedEntityKind kind, Entity *entity, Entity *other=nullptr) { ve->kind = kind; ve->entity = entity; ve->other = other; } -GB_COMPARE_PROC(vetted_entity_variable_pos_cmp) { +gb_internal GB_COMPARE_PROC(vetted_entity_variable_pos_cmp) { Entity *x = (cast(VettedEntity *)a)->entity; Entity *y = (cast(VettedEntity *)b)->entity; GB_ASSERT(x != nullptr); @@ -544,7 +544,7 @@ GB_COMPARE_PROC(vetted_entity_variable_pos_cmp) { return token_pos_cmp(x->token.pos, y->token.pos); } -bool check_vet_shadowing_assignment(Checker *c, Entity *shadowed, Ast *expr) { +gb_internal bool check_vet_shadowing_assignment(Checker *c, Entity *shadowed, Ast *expr) { Ast *init = unparen_expr(expr); if (init == nullptr) { return false; @@ -568,7 +568,7 @@ bool check_vet_shadowing_assignment(Checker *c, Entity *shadowed, Ast *expr) { } -bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) { +gb_internal bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) { if (e->kind != Entity_Variable) { return false; } @@ -634,7 +634,7 @@ bool check_vet_shadowing(Checker *c, Entity *e, VettedEntity *ve) { return true; } -bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { +gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { if ((e->flags&EntityFlag_Used) == 0) { switch (e->kind) { case Entity_Variable: @@ -652,7 +652,7 @@ bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { return false; } -void check_scope_usage(Checker *c, Scope *scope) { +gb_internal void check_scope_usage(Checker *c, Scope *scope) { bool vet_unused = true; bool vet_shadowing = true; @@ -728,12 +728,12 @@ void check_scope_usage(Checker *c, Scope *scope) { } -void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { +gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { mutex_lock(&info->deps_mutex); ptr_set_add(&d->deps, e); mutex_unlock(&info->deps_mutex); } -void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type, bool require_mutex) { +gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type, bool require_mutex) { if (d == nullptr) { return; } @@ -746,7 +746,7 @@ void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type, bool r } } -AstPackage *get_core_package(CheckerInfo *info, String name) { +gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { gbAllocator a = heap_allocator(); String path = get_fullpath_core(a, name); defer (gb_free(a, path.text)); @@ -764,7 +764,7 @@ AstPackage *get_core_package(CheckerInfo *info, String name) { } -void add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { +gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); Entity *e = scope_lookup(p->scope, n); @@ -774,7 +774,7 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co add_dependency(c->info, c->decl, e); } -void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { +gb_internal void try_to_add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); Entity *e = scope_lookup(p->scope, n); @@ -787,7 +787,7 @@ void try_to_add_package_dependency(CheckerContext *c, char const *package_name, } -void add_declaration_dependency(CheckerContext *c, Entity *e) { +gb_internal void add_declaration_dependency(CheckerContext *c, Entity *e) { if (e == nullptr) { return; } @@ -797,7 +797,7 @@ void add_declaration_dependency(CheckerContext *c, Entity *e) { } -Entity *add_global_entity(Entity *entity, Scope *scope=builtin_pkg->scope) { +gb_internal Entity *add_global_entity(Entity *entity, Scope *scope=builtin_pkg->scope) { String name = entity->token.string; defer (entity->state = EntityState_Resolved); @@ -810,27 +810,27 @@ Entity *add_global_entity(Entity *entity, Scope *scope=builtin_pkg->scope) { return entity; } -void add_global_constant(char const *name, Type *type, ExactValue value) { +gb_internal void add_global_constant(char const *name, Type *type, ExactValue value) { Entity *entity = alloc_entity(Entity_Constant, nullptr, make_token_ident(name), type); entity->Constant.value = value; add_global_entity(entity); } -void add_global_string_constant(char const *name, String const &value) { +gb_internal void add_global_string_constant(char const *name, String const &value) { add_global_constant(name, t_untyped_string, exact_value_string(value)); } -void add_global_bool_constant(char const *name, bool value) { +gb_internal void add_global_bool_constant(char const *name, bool value) { add_global_constant(name, t_untyped_bool, exact_value_bool(value)); } -void add_global_type_entity(String name, Type *type) { +gb_internal void add_global_type_entity(String name, Type *type) { add_global_entity(alloc_entity_type_name(nullptr, make_token_ident(name), type)); } -AstPackage *create_builtin_package(char const *name) { +gb_internal AstPackage *create_builtin_package(char const *name) { gbAllocator a = permanent_allocator(); AstPackage *pkg = gb_alloc_item(a, AstPackage); pkg->name = make_string_c(name); @@ -847,7 +847,7 @@ struct GlobalEnumValue { i64 value; }; -Slice add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr) { +gb_internal Slice add_global_enum_type(String const &type_name, GlobalEnumValue *values, isize value_count, Type **enum_type_ = nullptr) { Scope *scope = create_scope(nullptr, builtin_pkg->scope); Entity *entity = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); @@ -882,7 +882,7 @@ Slice add_global_enum_type(String const &type_name, GlobalEnumValue *v return slice_from_array(fields); } -void add_global_enum_constant(Slice const &fields, char const *name, i64 value) { +gb_internal void add_global_enum_constant(Slice const &fields, char const *name, i64 value) { for (Entity *field : fields) { GB_ASSERT(field->kind == Entity_Constant); if (value == exact_value_to_i64(field->Constant.value)) { @@ -893,7 +893,7 @@ void add_global_enum_constant(Slice const &fields, char const *name, i GB_PANIC("Unfound enum value for global constant: %s %lld", name, cast(long long)value); } -Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_type) { +gb_internal Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_type) { Entity *e = alloc_entity_type_name(scope, make_token_ident(type_name), nullptr, EntityState_Resolved); Type *named_type = alloc_type_named(type_name, backing_type, e); e->type = named_type; @@ -905,7 +905,7 @@ Type *add_global_type_name(Scope *scope, String const &type_name, Type *backing_ } -void init_universal(void) { +gb_internal void init_universal(void) { BuildContext *bc = &build_context; builtin_pkg = create_builtin_package("builtin"); @@ -1122,7 +1122,7 @@ void init_universal(void) { -void init_checker_info(CheckerInfo *i) { +gb_internal void init_checker_info(CheckerInfo *i) { gbAllocator a = heap_allocator(); TIME_SECTION("checker info: general"); @@ -1180,7 +1180,7 @@ void init_checker_info(CheckerInfo *i) { string_map_init(&i->load_file_cache, a); } -void destroy_checker_info(CheckerInfo *i) { +gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->definitions); array_free(&i->entities); map_destroy(&i->global_untyped); @@ -1217,7 +1217,7 @@ void destroy_checker_info(CheckerInfo *i) { string_map_destroy(&i->load_file_cache); } -CheckerContext make_checker_context(Checker *c) { +gb_internal CheckerContext make_checker_context(Checker *c) { CheckerContext ctx = {}; ctx.checker = c; ctx.info = &c->info; @@ -1230,12 +1230,12 @@ CheckerContext make_checker_context(Checker *c) { ctx.poly_level = 0; return ctx; } -void destroy_checker_context(CheckerContext *ctx) { +gb_internal void destroy_checker_context(CheckerContext *ctx) { destroy_checker_type_path(ctx->type_path); destroy_checker_poly_path(ctx->poly_path); } -void add_curr_ast_file(CheckerContext *ctx, AstFile *file) { +gb_internal void add_curr_ast_file(CheckerContext *ctx, AstFile *file) { if (file != nullptr) { ctx->file = file; ctx->decl = file->pkg->decl_info; @@ -1243,7 +1243,7 @@ void add_curr_ast_file(CheckerContext *ctx, AstFile *file) { ctx->pkg = file->pkg; } } -void reset_checker_context(CheckerContext *ctx, AstFile *file, UntypedExprInfoMap *untyped) { +gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, UntypedExprInfoMap *untyped) { if (ctx == nullptr) { return; } @@ -1258,7 +1258,7 @@ void reset_checker_context(CheckerContext *ctx, AstFile *file, UntypedExprInfoMa -void init_checker(Checker *c) { +gb_internal void init_checker(Checker *c) { gbAllocator a = heap_allocator(); TIME_SECTION("init checker info"); @@ -1278,7 +1278,7 @@ void init_checker(Checker *c) { c->builtin_ctx = make_checker_context(c); } -void destroy_checker(Checker *c) { +gb_internal void destroy_checker(Checker *c) { destroy_checker_info(&c->info); destroy_checker_context(&c->builtin_ctx); @@ -1290,7 +1290,7 @@ void destroy_checker(Checker *c) { } -TypeAndValue type_and_value_of_expr(Ast *expr) { +gb_internal TypeAndValue type_and_value_of_expr(Ast *expr) { TypeAndValue tav = {}; if (expr != nullptr) { tav = expr->tav; @@ -1298,7 +1298,7 @@ TypeAndValue type_and_value_of_expr(Ast *expr) { return tav; } -Type *type_of_expr(Ast *expr) { +gb_internal Type *type_of_expr(Ast *expr) { TypeAndValue tav = expr->tav; if (tav.mode != Addressing_Invalid) { return tav.type; @@ -1313,14 +1313,14 @@ Type *type_of_expr(Ast *expr) { return nullptr; } -Entity *implicit_entity_of_node(Ast *clause) { +gb_internal Entity *implicit_entity_of_node(Ast *clause) { if (clause != nullptr && clause->kind == Ast_CaseClause) { return clause->CaseClause.implicit_entity; } return nullptr; } -Entity *entity_of_node(Ast *expr) { +gb_internal Entity *entity_of_node(Ast *expr) { expr = unparen_expr(expr); switch (expr->kind) { case_ast_node(ident, Ident, expr); @@ -1341,25 +1341,25 @@ Entity *entity_of_node(Ast *expr) { return nullptr; } -DeclInfo *decl_info_of_entity(Entity *e) { +gb_internal DeclInfo *decl_info_of_entity(Entity *e) { if (e != nullptr) { return e->decl_info; } return nullptr; } -DeclInfo *decl_info_of_ident(Ast *ident) { +gb_internal DeclInfo *decl_info_of_ident(Ast *ident) { return decl_info_of_entity(entity_of_node(ident)); } -AstFile *ast_file_of_filename(CheckerInfo *i, String filename) { +gb_internal AstFile *ast_file_of_filename(CheckerInfo *i, String filename) { AstFile **found = string_map_get(&i->files, filename); if (found != nullptr) { return *found; } return nullptr; } -ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { +gb_internal ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { if (c->untyped != nullptr) { ExprInfo **found = map_get(c->untyped, expr); if (found) { @@ -1377,7 +1377,7 @@ ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { } } -void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { if (c->untyped != nullptr) { map_set(c->untyped, expr, make_expr_info(mode, type, value, false)); } else { @@ -1387,7 +1387,7 @@ void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMode mode, Type } } -void check_remove_expr_info(CheckerContext *c, Ast *e) { +gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { if (c->untyped != nullptr) { map_remove(c->untyped, e); GB_ASSERT(map_get(c->untyped, e) == nullptr); @@ -1401,7 +1401,7 @@ void check_remove_expr_info(CheckerContext *c, Ast *e) { } -isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) { +gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) { type = default_type(type); if (type == t_llvm_bool) { type = t_bool; @@ -1436,7 +1436,7 @@ isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) { } -void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { if (expr == nullptr) { return; } @@ -1453,7 +1453,7 @@ void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, check_set_expr_info(c, expr, mode, type, value); } -void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { if (expr == nullptr) { return; } @@ -1489,7 +1489,7 @@ void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *ty mutex_unlock(&i->type_and_value_mutex); } -void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { +gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { GB_ASSERT(identifier != nullptr); GB_ASSERT(identifier->kind == Ast_Ident); // if (is_blank_ident(identifier)) { @@ -1505,7 +1505,7 @@ void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { mpmc_enqueue(&i->definition_queue, entity); } -bool redeclaration_error(String name, Entity *prev, Entity *found) { +gb_internal bool redeclaration_error(String name, Entity *prev, Entity *found) { TokenPos pos = found->token.pos; Entity *up = found->using_parent; if (up != nullptr) { @@ -1548,7 +1548,7 @@ bool redeclaration_error(String name, Entity *prev, Entity *found) { return false; } -void add_entity_flags_from_file(CheckerContext *c, Entity *e, Scope *scope) { +gb_internal void add_entity_flags_from_file(CheckerContext *c, Entity *e, Scope *scope) { if (c->file != nullptr && (c->file->flags & AstFile_IsLazy) != 0 && scope->flags & ScopeFlag_File) { AstPackage *pkg = c->file->pkg; if (pkg->kind == Package_Init && e->kind == Entity_Procedure && e->token.string == "main") { @@ -1561,7 +1561,7 @@ void add_entity_flags_from_file(CheckerContext *c, Entity *e, Scope *scope) { } } -bool add_entity_with_name(CheckerContext *c, Scope *scope, Ast *identifier, Entity *entity, String name) { +gb_internal bool add_entity_with_name(CheckerContext *c, Scope *scope, Ast *identifier, Entity *entity, String name) { if (scope == nullptr) { return false; } @@ -1581,11 +1581,11 @@ bool add_entity_with_name(CheckerContext *c, Scope *scope, Ast *identifier, Enti } return true; } -bool add_entity(CheckerContext *c, Scope *scope, Ast *identifier, Entity *entity) { +gb_internal bool add_entity(CheckerContext *c, Scope *scope, Ast *identifier, Entity *entity) { return add_entity_with_name(c, scope, identifier, entity, entity->token.string); } -void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) { +gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) { if (entity == nullptr) { return; } @@ -1622,7 +1622,7 @@ void add_entity_use(CheckerContext *c, Ast *identifier, Entity *entity) { } -bool could_entity_be_lazy(Entity *e, DeclInfo *d) { +gb_internal bool could_entity_be_lazy(Entity *e, DeclInfo *d) { if ((e->flags & EntityFlag_Lazy) == 0) { return false; } @@ -1673,7 +1673,7 @@ bool could_entity_be_lazy(Entity *e, DeclInfo *d) { return true; } -void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported) { +gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported) { if (identifier == nullptr) { // NOTE(bill): Should only happen on errors error(e->token, "Invalid variable declaration"); @@ -1738,16 +1738,15 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec } -void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) { +gb_internal void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) { GB_ASSERT(clause != nullptr); GB_ASSERT(e != nullptr); GB_ASSERT(clause->kind == Ast_CaseClause); clause->CaseClause.implicit_entity = e; } -void add_type_info_type(CheckerContext *c, Type *t) { - void add_type_info_type_internal(CheckerContext *c, Type *t); - +gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t); +gb_internal void add_type_info_type(CheckerContext *c, Type *t) { if (build_context.disallow_rtti) { return; } @@ -1757,7 +1756,7 @@ void add_type_info_type(CheckerContext *c, Type *t) { mutex_unlock(&c->info->type_info_mutex); } -void add_type_info_type_internal(CheckerContext *c, Type *t) { +gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { if (t == nullptr) { return; } @@ -1982,7 +1981,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { gb_global bool global_procedure_body_in_worker_queue = false; -void check_procedure_later(CheckerContext *c, ProcInfo *info) { +gb_internal void check_procedure_later(CheckerContext *c, ProcInfo *info) { GB_ASSERT(info != nullptr); GB_ASSERT(info->decl != nullptr); @@ -1994,7 +1993,7 @@ void check_procedure_later(CheckerContext *c, ProcInfo *info) { mpmc_enqueue(queue, info); } -void check_procedure_later(CheckerContext *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { +gb_internal void check_procedure_later(CheckerContext *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { ProcInfo *info = gb_alloc_item(permanent_allocator(), ProcInfo); info->file = file; info->token = token; @@ -2006,7 +2005,7 @@ void check_procedure_later(CheckerContext *c, AstFile *file, Token token, DeclIn } -void add_min_dep_type_info(Checker *c, Type *t) { +gb_internal void add_min_dep_type_info(Checker *c, Type *t) { if (t == nullptr) { return; } @@ -2201,7 +2200,7 @@ void add_min_dep_type_info(Checker *c, Type *t) { } -void add_dependency_to_set(Checker *c, Entity *entity) { +gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { if (entity == nullptr) { return; } @@ -2254,7 +2253,7 @@ void add_dependency_to_set(Checker *c, Entity *entity) { } } -void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { +gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { Entity *e = scope_lookup(scope, name); if (e == nullptr) { return; @@ -2266,7 +2265,7 @@ void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { -void generate_minimum_dependency_set(Checker *c, Entity *start) { +gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { isize entity_count = c->info.entities.count; isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor @@ -2479,7 +2478,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { #undef FORCE_ADD_RUNTIME_ENTITIES } -bool is_entity_a_dependency(Entity *e) { +gb_internal bool is_entity_a_dependency(Entity *e) { if (e == nullptr) return false; switch (e->kind) { case Entity_Procedure: @@ -2493,7 +2492,7 @@ bool is_entity_a_dependency(Entity *e) { return false; } -Array generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) { +gb_internal Array generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) { PtrMap M = {}; map_init(&M, allocator, info->entities.count); defer (map_destroy(&M)); @@ -2612,10 +2611,10 @@ Array generate_entity_dependency_graph(CheckerInfo *info, gbA } -void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d); +gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d); -Entity *find_core_entity(Checker *c, String name) { +gb_internal Entity *find_core_entity(Checker *c, String name) { Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" @@ -2625,7 +2624,7 @@ Entity *find_core_entity(Checker *c, String name) { return e; } -Type *find_core_type(Checker *c, String name) { +gb_internal Type *find_core_type(Checker *c, String name) { Entity *e = scope_lookup_current(c->info.runtime_package->scope, name); if (e == nullptr) { compiler_error("Could not find type declaration for '%.*s'\n" @@ -2640,7 +2639,7 @@ Type *find_core_type(Checker *c, String name) { } -Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { +gb_internal Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { AstPackage *package = get_core_package(info, pkg); Entity *e = scope_lookup_current(package->scope, name); if (e == nullptr) { @@ -2650,7 +2649,7 @@ Entity *find_entity_in_pkg(CheckerInfo *info, String const &pkg, String const &n return e; } -Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { +gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String const &name) { AstPackage *package = get_core_package(info, pkg); Entity *e = scope_lookup_current(package->scope, name); if (e == nullptr) { @@ -2661,58 +2660,58 @@ Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String const &name) return e->type; } -CheckerTypePath *new_checker_type_path() { +gb_internal CheckerTypePath *new_checker_type_path() { gbAllocator a = heap_allocator(); auto *tp = gb_alloc_item(a, CheckerTypePath); array_init(tp, a, 0, 16); return tp; } -void destroy_checker_type_path(CheckerTypePath *tp) { +gb_internal void destroy_checker_type_path(CheckerTypePath *tp) { array_free(tp); gb_free(heap_allocator(), tp); } -void check_type_path_push(CheckerContext *c, Entity *e) { +gb_internal void check_type_path_push(CheckerContext *c, Entity *e) { GB_ASSERT(c->type_path != nullptr); GB_ASSERT(e != nullptr); array_add(c->type_path, e); } -Entity *check_type_path_pop(CheckerContext *c) { +gb_internal Entity *check_type_path_pop(CheckerContext *c) { GB_ASSERT(c->type_path != nullptr); return array_pop(c->type_path); } -CheckerPolyPath *new_checker_poly_path(void) { +gb_internal CheckerPolyPath *new_checker_poly_path(void) { gbAllocator a = heap_allocator(); auto *pp = gb_alloc_item(a, CheckerPolyPath); array_init(pp, a, 0, 16); return pp; } -void destroy_checker_poly_path(CheckerPolyPath *pp) { +gb_internal void destroy_checker_poly_path(CheckerPolyPath *pp) { array_free(pp); gb_free(heap_allocator(), pp); } -void check_poly_path_push(CheckerContext *c, Type *t) { +gb_internal void check_poly_path_push(CheckerContext *c, Type *t) { GB_ASSERT(c->poly_path != nullptr); GB_ASSERT(t != nullptr); GB_ASSERT(is_type_polymorphic(t)); array_add(c->poly_path, t); } -Type *check_poly_path_pop(CheckerContext *c) { +gb_internal Type *check_poly_path_pop(CheckerContext *c) { GB_ASSERT(c->poly_path != nullptr); return array_pop(c->poly_path); } -Array proc_group_entities(CheckerContext *c, Operand o) { +gb_internal Array proc_group_entities(CheckerContext *c, Operand o) { Array procs = {}; if (o.mode == Addressing_ProcGroup) { GB_ASSERT(o.proc_group != nullptr); @@ -2724,7 +2723,7 @@ Array proc_group_entities(CheckerContext *c, Operand o) { return procs; } -Array proc_group_entities_cloned(CheckerContext *c, Operand o) { +gb_internal Array proc_group_entities_cloned(CheckerContext *c, Operand o) { auto entities = proc_group_entities(c, o); if (entities.count == 0) { return {}; @@ -2735,7 +2734,7 @@ Array proc_group_entities_cloned(CheckerContext *c, Operand o) { -void init_core_type_info(Checker *c) { +gb_internal void init_core_type_info(Checker *c) { if (t_type_info != nullptr) { return; } @@ -2816,7 +2815,7 @@ void init_core_type_info(Checker *c) { t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); } -void init_mem_allocator(Checker *c) { +gb_internal void init_mem_allocator(Checker *c) { if (t_allocator != nullptr) { return; } @@ -2825,7 +2824,7 @@ void init_mem_allocator(Checker *c) { t_allocator_error = find_core_type(c, str_lit("Allocator_Error")); } -void init_core_context(Checker *c) { +gb_internal void init_core_context(Checker *c) { if (t_context != nullptr) { return; } @@ -2833,7 +2832,7 @@ void init_core_context(Checker *c) { t_context_ptr = alloc_type_pointer(t_context); } -void init_core_source_code_location(Checker *c) { +gb_internal void init_core_source_code_location(Checker *c) { if (t_source_code_location != nullptr) { return; } @@ -2841,7 +2840,7 @@ void init_core_source_code_location(Checker *c) { t_source_code_location_ptr = alloc_type_pointer(t_source_code_location); } -void init_core_map_type(Checker *c) { +gb_internal void init_core_map_type(Checker *c) { if (t_map_info != nullptr) { return; } @@ -2855,7 +2854,7 @@ void init_core_map_type(Checker *c) { t_raw_map_ptr = alloc_type_pointer(t_raw_map); } -void init_preload(Checker *c) { +gb_internal void init_preload(Checker *c) { init_core_type_info(c); init_mem_allocator(c); init_core_context(c); @@ -2863,7 +2862,7 @@ void init_preload(Checker *c) { init_core_map_type(c); } -ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { +gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { ExactValue ev = {}; if (value != nullptr) { Operand op = {}; @@ -2879,7 +2878,7 @@ ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { return ev; } -Type *check_decl_attribute_type(CheckerContext *c, Ast *value) { +gb_internal Type *check_decl_attribute_type(CheckerContext *c, Ast *value) { if (value != nullptr) { return check_type(c, value); } @@ -2890,7 +2889,7 @@ Type *check_decl_attribute_type(CheckerContext *c, Ast *value) { #define ATTRIBUTE_USER_TAG_NAME "tag" -DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (name == ATTRIBUTE_USER_TAG_NAME) { @@ -2945,7 +2944,7 @@ DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return false; } -DECL_ATTRIBUTE_PROC(proc_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (name == ATTRIBUTE_USER_TAG_NAME) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind != ExactValue_String) { @@ -3242,7 +3241,7 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) { return false; } -DECL_ATTRIBUTE_PROC(var_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { if (name == ATTRIBUTE_USER_TAG_NAME) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind != ExactValue_String) { @@ -3367,7 +3366,7 @@ DECL_ATTRIBUTE_PROC(var_decl_attribute) { return false; } -DECL_ATTRIBUTE_PROC(const_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(const_decl_attribute) { if (name == ATTRIBUTE_USER_TAG_NAME) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind != ExactValue_String) { @@ -3381,7 +3380,7 @@ DECL_ATTRIBUTE_PROC(const_decl_attribute) { return false; } -DECL_ATTRIBUTE_PROC(type_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { if (name == ATTRIBUTE_USER_TAG_NAME) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind != ExactValue_String) { @@ -3412,7 +3411,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { -void check_decl_attributes(CheckerContext *c, Array const &attributes, DeclAttributeProc *proc, AttributeContext *ac) { +gb_internal void check_decl_attributes(CheckerContext *c, Array const &attributes, DeclAttributeProc *proc, AttributeContext *ac) { if (attributes.count == 0) return; String original_link_prefix = {}; @@ -3480,7 +3479,7 @@ void check_decl_attributes(CheckerContext *c, Array const &attributes, De } -isize get_total_value_count(Slice const &values) { +gb_internal isize get_total_value_count(Slice const &values) { isize count = 0; for_array(i, values) { Type *t = type_of_expr(values[i]); @@ -3498,7 +3497,7 @@ isize get_total_value_count(Slice const &values) { return count; } -bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global) { +gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global) { isize lhs = vd->names.count; isize rhs = 0; if (is_global) { @@ -3541,7 +3540,7 @@ bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global) { return true; } -void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws) { +gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws) { Operand operand = {Addressing_Invalid}; if (!ws->is_cond_determined) { check_expr(c, &operand, ws->cond); @@ -3577,7 +3576,7 @@ void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws) { } } -void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array *attributes) { +gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array *attributes) { switch (e->kind) { case Entity_ProcGroup: case Entity_Procedure: @@ -3640,7 +3639,7 @@ void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array *attr } } -void check_collect_value_decl(CheckerContext *c, Ast *decl) { +gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (decl->state_flags & StateFlag_BeenHandled) return; decl->state_flags |= StateFlag_BeenHandled; @@ -3891,7 +3890,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } } -void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) { +gb_internal void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) { if (decl->state_flags & StateFlag_BeenHandled) return; decl->state_flags |= StateFlag_BeenHandled; @@ -3912,7 +3911,7 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) { check_collect_entities(&c, block->stmts); } -bool correct_single_type_alias(CheckerContext *c, Entity *e) { +gb_internal bool correct_single_type_alias(CheckerContext *c, Entity *e) { if (e->kind == Entity_Constant) { DeclInfo *d = e->decl_info; if (d != nullptr && d->init_expr != nullptr) { @@ -3927,7 +3926,7 @@ bool correct_single_type_alias(CheckerContext *c, Entity *e) { return false; } -bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { +gb_internal bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { isize n = s->elements.entries.count; bool correction = false; for (isize i = n-1; i >= 0; i--) { @@ -3935,7 +3934,7 @@ bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { } return correction; } -bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) { +gb_internal bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) { isize n = s->elements.entries.count; bool correction = false; for (isize i = 0; i < n; i++) { @@ -3945,7 +3944,7 @@ bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) { } -void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { +gb_internal void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { // NOTE(bill, 2022-02-04): This is used to solve the problem caused by type aliases // of type aliases being "confused" as constants // @@ -3966,7 +3965,7 @@ void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { // NOTE(bill): If file_scopes == nullptr, this will act like a local scope -void check_collect_entities(CheckerContext *c, Slice const &nodes) { +gb_internal void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; if ((c->scope->flags&ScopeFlag_File) != 0) { curr_file = c->scope->file; @@ -4050,13 +4049,13 @@ void check_collect_entities(CheckerContext *c, Slice const &nodes) { } } -CheckerContext *create_checker_context(Checker *c) { +gb_internal CheckerContext *create_checker_context(Checker *c) { CheckerContext *ctx = gb_alloc_item(permanent_allocator(), CheckerContext); *ctx = make_checker_context(c); return ctx; } -void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) { +gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) { GB_ASSERT(e != nullptr); GB_ASSERT(d != nullptr); @@ -4089,7 +4088,7 @@ void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) { check_entity_decl(ctx, e, d, nullptr); } -void check_all_global_entities(Checker *c) { +gb_internal void check_all_global_entities(Checker *c) { // NOTE(bill): This must be single threaded // Don't bother trying for_array(i, c->info.entities) { @@ -4107,7 +4106,7 @@ void check_all_global_entities(Checker *c) { } -bool is_string_an_identifier(String s) { +gb_internal bool is_string_an_identifier(String s) { isize offset = 0; if (s.len < 1) { return false; @@ -4131,7 +4130,7 @@ bool is_string_an_identifier(String s) { return offset == s.len; } -String path_to_entity_name(String name, String fullpath, bool strip_extension=true) { +gb_internal String path_to_entity_name(String name, String fullpath, bool strip_extension=true) { if (name.len != 0) { return name; } @@ -4177,7 +4176,7 @@ String path_to_entity_name(String name, String fullpath, bool strip_extension=tr #if 1 -void add_import_dependency_node(Checker *c, Ast *decl, PtrMap *M) { +gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap *M) { AstPackage *parent_pkg = decl->file()->pkg; switch (decl->kind) { @@ -4242,7 +4241,7 @@ void add_import_dependency_node(Checker *c, Ast *decl, PtrMap generate_import_dependency_graph(Checker *c) { +gb_internal Array generate_import_dependency_graph(Checker *c) { PtrMap M = {}; map_init(&M, heap_allocator(), 2*c->parser->packages.count); defer (map_destroy(&M)); @@ -4285,7 +4284,7 @@ struct ImportPathItem { Ast * decl; }; -Array find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet *visited) { +gb_internal Array find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet *visited) { Array empty_path = {}; if (ptr_set_update(visited, start)) { @@ -4335,7 +4334,7 @@ Array find_import_path(Checker *c, AstPackage *start, AstPackage } #endif -String get_invalid_import_name(String input) { +gb_internal String get_invalid_import_name(String input) { isize slash = 0; for (isize i = input.len-1; i >= 0; i--) { if (input[i] == '/' || input[i] == '\\') { @@ -4347,7 +4346,7 @@ String get_invalid_import_name(String input) { return input; } -void check_add_import_decl(CheckerContext *ctx, Ast *decl) { +gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { if (decl->state_flags & StateFlag_BeenHandled) return; decl->state_flags |= StateFlag_BeenHandled; @@ -4422,7 +4421,7 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { scope->flags |= ScopeFlag_HasBeenImported; } -DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { +gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { if (name == ATTRIBUTE_USER_TAG_NAME) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind != ExactValue_String) { @@ -4449,7 +4448,7 @@ DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { return false; } -void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { +gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { if (decl->state_flags & StateFlag_BeenHandled) return; decl->state_flags |= StateFlag_BeenHandled; @@ -4515,10 +4514,10 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { } // Returns true if a new package is present -bool collect_file_decls(CheckerContext *ctx, Slice const &decls); -bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws); +gb_internal bool collect_file_decls(CheckerContext *ctx, Slice const &decls); +gb_internal bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws); -bool collect_when_stmt_from_file(CheckerContext *ctx, AstWhenStmt *ws) { +gb_internal bool collect_when_stmt_from_file(CheckerContext *ctx, AstWhenStmt *ws) { Operand operand = {Addressing_Invalid}; if (!ws->is_cond_determined) { check_expr(ctx, &operand, ws->cond); @@ -4557,7 +4556,7 @@ bool collect_when_stmt_from_file(CheckerContext *ctx, AstWhenStmt *ws) { return false; } -bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws) { +gb_internal bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws) { Operand operand = {Addressing_Invalid}; if (!ws->is_cond_determined) { check_expr(ctx, &operand, ws->cond); @@ -4594,7 +4593,7 @@ bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws) { } -bool collect_file_decl(CheckerContext *ctx, Ast *decl) { +gb_internal bool collect_file_decl(CheckerContext *ctx, Ast *decl) { GB_ASSERT(ctx->scope->flags&ScopeFlag_File); AstFile *curr_file = ctx->scope->file; @@ -4658,7 +4657,7 @@ bool collect_file_decl(CheckerContext *ctx, Ast *decl) { return false; } -bool collect_file_decls(CheckerContext *ctx, Slice const &decls) { +gb_internal bool collect_file_decls(CheckerContext *ctx, Slice const &decls) { GB_ASSERT(ctx->scope->flags&ScopeFlag_File); for_array(i, decls) { @@ -4671,7 +4670,7 @@ bool collect_file_decls(CheckerContext *ctx, Slice const &decls) { return false; } -GB_COMPARE_PROC(sort_file_by_name) { +gb_internal GB_COMPARE_PROC(sort_file_by_name) { AstFile const *x = *cast(AstFile const **)a; AstFile const *y = *cast(AstFile const **)b; String x_name = filename_from_path(x->fullpath); @@ -4679,7 +4678,7 @@ GB_COMPARE_PROC(sort_file_by_name) { return string_compare(x_name, y_name); } -void check_create_file_scopes(Checker *c) { +gb_internal void check_create_file_scopes(Checker *c) { for_array(i, c->parser->packages) { AstPackage *pkg = c->parser->packages[i]; isize total_pkg_decl_count = 0; @@ -4705,7 +4704,7 @@ struct ThreadProcCheckerSection { }; -void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) { +gb_internal void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) { isize thread_count = gb_max(build_context.thread_count, 1); isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work if (!build_context.threaded_checker) { @@ -4744,7 +4743,7 @@ void check_with_workers(Checker *c, WorkerTaskProc *proc, isize total_count) { } -WORKER_TASK_PROC(thread_proc_collect_entities) { +gb_internal WORKER_TASK_PROC(thread_proc_collect_entities) { auto *cs = cast(ThreadProcCheckerSection *)data; Checker *c = cs->checker; CheckerContext collect_entity_ctx = make_checker_context(c); @@ -4775,11 +4774,11 @@ WORKER_TASK_PROC(thread_proc_collect_entities) { } -void check_collect_entities_all(Checker *c) { +gb_internal void check_collect_entities_all(Checker *c) { check_with_workers(c, thread_proc_collect_entities, c->info.files.entries.count); } -void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *pkg, UntypedExprInfoMap *untyped) { +gb_internal void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *pkg, UntypedExprInfoMap *untyped) { if (pkg->files.count != 0) { AstPackageExportedEntity item = {}; while (mpmc_dequeue(&pkg->exported_entity_queue, &item)) { @@ -4793,7 +4792,7 @@ void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *pkg, UntypedE } } -WORKER_TASK_PROC(thread_proc_check_export_entities) { +gb_internal WORKER_TASK_PROC(thread_proc_check_export_entities) { auto cs = cast(ThreadProcCheckerSection *)data; Checker *c = cs->checker; @@ -4815,11 +4814,11 @@ WORKER_TASK_PROC(thread_proc_check_export_entities) { return 0; } -void check_export_entities(Checker *c) { +gb_internal void check_export_entities(Checker *c) { check_with_workers(c, thread_proc_check_export_entities, c->info.packages.entries.count); } -void check_import_entities(Checker *c) { +gb_internal void check_import_entities(Checker *c) { Array dep_graph = generate_import_dependency_graph(c); defer ({ for_array(i, dep_graph) { @@ -4961,9 +4960,9 @@ void check_import_entities(Checker *c) { } -Array find_entity_path(Entity *start, Entity *end, PtrSet *visited = nullptr); +gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet *visited = nullptr); -bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet *visited, Array *path_) { +gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet *visited, Array *path_) { GB_ASSERT(path_ != nullptr); if (tuple == nullptr) { return false; @@ -4995,7 +4994,7 @@ bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet *visited, return false; } -Array find_entity_path(Entity *start, Entity *end, PtrSet *visited) { +gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet *visited) { PtrSet visited_ = {}; bool made_visited = false; if (visited == nullptr) { @@ -5047,7 +5046,7 @@ Array find_entity_path(Entity *start, Entity *end, PtrSet *v } -void calculate_global_init_order(Checker *c) { +gb_internal void calculate_global_init_order(Checker *c) { CheckerInfo *info = &c->info; TIME_SECTION("calculate_global_init_order: generate entity dependency graph"); @@ -5122,7 +5121,7 @@ void calculate_global_init_order(Checker *c) { } -bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, ProcBodyQueue *procs_to_check_queue) { +gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, ProcBodyQueue *procs_to_check_queue) { if (pi == nullptr) { return false; } @@ -5201,9 +5200,9 @@ bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, Proc GB_STATIC_ASSERT(sizeof(isize) == sizeof(void *)); -bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped); +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped); -void check_unchecked_bodies(Checker *c) { +gb_internal void check_unchecked_bodies(Checker *c) { // NOTE(2021-02-26, bill): Sanity checker // This is a partial hack to make sure all procedure bodies have been checked // even ones which should not exist, due to the multithreaded nature of the parser @@ -5255,7 +5254,7 @@ void check_unchecked_bodies(Checker *c) { } -void check_test_procedures(Checker *c) { +gb_internal void check_test_procedures(Checker *c) { if (build_context.test_names.entries.count == 0) { return; } @@ -5290,7 +5289,7 @@ void check_test_procedures(Checker *c) { gb_global std::atomic total_bodies_checked; -bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped) { +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped) { GB_ASSERT(pi->decl != nullptr); if (pi->decl->parent && pi->decl->parent->entity) { Entity *parent = pi->decl->parent->entity; @@ -5318,7 +5317,7 @@ struct ThreadProcBodyData { ThreadProcBodyData *all_data; }; -WORKER_TASK_PROC(thread_proc_body) { +gb_internal WORKER_TASK_PROC(thread_proc_body) { ThreadProcBodyData *bd = cast(ThreadProcBodyData *)data; Checker *c = bd->checker; GB_ASSERT(c != nullptr); @@ -5338,7 +5337,7 @@ WORKER_TASK_PROC(thread_proc_body) { return 0; } -void check_procedure_bodies(Checker *c) { +gb_internal void check_procedure_bodies(Checker *c) { GB_ASSERT(c != nullptr); u32 thread_count = cast(u32)gb_max(build_context.thread_count, 1); @@ -5414,7 +5413,7 @@ void check_procedure_bodies(Checker *c) { global_procedure_body_in_worker_queue = false; } -void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) { +gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) { if (untyped == nullptr) { return; } @@ -5428,7 +5427,7 @@ void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) { map_clear(untyped); } -void check_deferred_procedures(Checker *c) { +gb_internal void check_deferred_procedures(Checker *c) { for (Entity *src = nullptr; mpmc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) { GB_ASSERT(src->kind == Entity_Procedure); @@ -5581,7 +5580,7 @@ void check_deferred_procedures(Checker *c) { } -void check_unique_package_names(Checker *c) { +gb_internal void check_unique_package_names(Checker *c) { StringMap pkgs = {}; // Key: package name string_map_init(&pkgs, heap_allocator(), 2*c->info.packages.entries.count); defer (string_map_destroy(&pkgs)); @@ -5614,7 +5613,7 @@ void check_unique_package_names(Checker *c) { } } -void check_add_entities_from_queues(Checker *c) { +gb_internal void check_add_entities_from_queues(Checker *c) { isize cap = c->info.entities.count + c->info.entity_queue.count.load(std::memory_order_relaxed); array_reserve(&c->info.entities, cap); for (Entity *e; mpmc_dequeue(&c->info.entity_queue, &e); /**/) { @@ -5622,7 +5621,7 @@ void check_add_entities_from_queues(Checker *c) { } } -void check_add_definitions_from_queues(Checker *c) { +gb_internal void check_add_definitions_from_queues(Checker *c) { isize cap = c->info.definitions.count + c->info.definition_queue.count.load(std::memory_order_relaxed); array_reserve(&c->info.definitions, cap); for (Entity *e; mpmc_dequeue(&c->info.definition_queue, &e); /**/) { @@ -5630,12 +5629,12 @@ void check_add_definitions_from_queues(Checker *c) { } } -void check_merge_queues_into_arrays(Checker *c) { +gb_internal void check_merge_queues_into_arrays(Checker *c) { check_add_entities_from_queues(c); check_add_definitions_from_queues(c); } -GB_COMPARE_PROC(init_procedures_cmp) { +gb_internal GB_COMPARE_PROC(init_procedures_cmp) { int cmp = 0; Entity *x = *(Entity **)a; Entity *y = *(Entity **)b; @@ -5673,11 +5672,11 @@ GB_COMPARE_PROC(init_procedures_cmp) { } -void check_sort_init_procedures(Checker *c) { +gb_internal void check_sort_init_procedures(Checker *c) { gb_sort_array(c->info.init_procedures.data, c->info.init_procedures.count, init_procedures_cmp); } -void add_type_info_for_type_definitions(Checker *c) { +gb_internal void add_type_info_for_type_definitions(Checker *c) { for_array(i, c->info.definitions) { Entity *e = c->info.definitions[i]; if (e->kind == Entity_TypeName && e->type != nullptr) { @@ -5689,7 +5688,7 @@ void add_type_info_for_type_definitions(Checker *c) { } } -void check_parsed_files(Checker *c) { +gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("map full filepaths to scope"); add_type_info_type(&c->builtin_ctx, t_invalid); diff --git a/src/types.cpp b/src/types.cpp index 2ab7374c2..c8e24f01d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4029,9 +4029,8 @@ gb_internal bool has_type_got_objc_class_attribute(Type *t) { +gb_internal bool internal_check_is_assignable_to(Type *src, Type *dst); gb_internal bool is_type_objc_object(Type *t) { - bool internal_check_is_assignable_to(Type *src, Type *dst); - return internal_check_is_assignable_to(t, t_objc_object); } -- cgit v1.2.3 From c1f5be24e28c41efbbbe6d116d533b55d48bbf82 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 18 Dec 2022 22:49:10 +0000 Subject: Remove dead code in the compiler --- build.bat | 1 + src/build_settings.cpp | 6 +- src/check_decl.cpp | 10 - src/check_expr.cpp | 24 - src/check_stmt.cpp | 6 - src/checker.cpp | 140 ++---- src/checker.hpp | 8 - src/common.cpp | 9 + src/docs.cpp | 9 - src/entity.cpp | 8 - src/exact_value.cpp | 86 ++-- src/llvm_backend.cpp | 10 +- src/llvm_backend_debug.cpp | 6 - src/llvm_backend_general.cpp | 68 --- src/llvm_backend_opt.cpp | 20 +- src/llvm_backend_proc.cpp | 88 ++-- src/llvm_backend_stmt.cpp | 10 - src/llvm_backend_utility.cpp | 12 - src/main.cpp | 77 +--- src/parser.cpp | 36 -- src/parser.hpp | 5 - src/parser_pos.cpp | 2 - src/query_data.cpp | 1030 ------------------------------------------ src/range_cache.cpp | 18 +- src/string.cpp | 14 - src/string_map.cpp | 2 - src/threading.cpp | 50 +- src/types.cpp | 75 --- 28 files changed, 169 insertions(+), 1661 deletions(-) delete mode 100644 src/query_data.cpp (limited to 'src/check_expr.cpp') diff --git a/build.bat b/build.bat index 7391bd95f..d7a89fe20 100644 --- a/build.bat +++ b/build.bat @@ -62,6 +62,7 @@ if %release_mode% EQU 0 ( rem Debug set compiler_warnings= ^ -W4 -WX ^ -wd4100 -wd4101 -wd4127 -wd4146 ^ + -wd4505 ^ -wd4456 -wd4457 set compiler_includes= ^ diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d66db8099..7d796d775 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -149,7 +149,6 @@ enum CommandKind : u32 { Command_run = 1<<0, Command_build = 1<<1, Command_check = 1<<3, - Command_query = 1<<4, Command_doc = 1<<5, Command_version = 1<<6, Command_test = 1<<7, @@ -157,7 +156,7 @@ enum CommandKind : u32 { Command_strip_semicolon = 1<<8, Command_bug_report = 1<<9, - Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test|Command_strip_semicolon, + Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon, Command__does_build = Command_run|Command_build|Command_test, Command_all = ~(u32)0, }; @@ -166,7 +165,6 @@ gb_global char const *odin_command_strings[32] = { "run", "build", "check", - "query", "doc", "version", "test", @@ -316,8 +314,6 @@ struct BuildContext { u32 cmd_doc_flags; Array extra_packages; - QueryDataSetSettings query_data_set_settings; - StringSet test_names; gbAffinity affinity; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index a976c1b73..d982a69fc 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -232,16 +232,6 @@ gb_internal Ast *remove_type_alias_clutter(Ast *node) { } } -gb_internal isize total_attribute_count(DeclInfo *decl) { - isize attribute_count = 0; - for_array(i, decl->attributes) { - Ast *attr = decl->attributes[i]; - if (attr->kind != Ast_Attribute) continue; - attribute_count += attr->Attribute.elems.count; - } - return attribute_count; -} - gb_internal Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) { // NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations // diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3003e07b6..ed1ddd1f1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5103,16 +5103,6 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize return optional_ok; } - -gb_internal bool is_expr_constant_zero(Ast *expr) { - GB_ASSERT(expr != nullptr); - auto v = exact_value_to_integer(expr->tav.value); - if (v.kind == ExactValue_Integer) { - return big_int_cmp_zero(&v.value_integer) == 0; - } - return false; -} - gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_) { GB_ASSERT(pt != nullptr); GB_ASSERT(pt->kind == Type_Proc); @@ -5429,20 +5419,6 @@ gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name } return -1; } -gb_internal isize lookup_procedure_result(TypeProc *pt, String result_name) { - isize result_count = pt->result_count; - for (isize i = 0; i < result_count; i++) { - Entity *e = pt->results->Tuple.variables[i]; - String name = e->token.string; - if (is_blank_ident(name)) { - continue; - } - if (name == result_name) { - return i; - } - } - return -1; -} gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { ast_node(ce, CallExpr, call); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index cae9c3537..73adbed8b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1520,12 +1520,6 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) } case_end; - case_ast_node(ts, TagStmt, node); - // TODO(bill): Tag Statements - error(node, "Tag statements are not supported yet"); - check_stmt(ctx, ts->stmt, flags); - case_end; - case_ast_node(as, AssignStmt, node); switch (as->op.kind) { case Token_Eq: { diff --git a/src/checker.cpp b/src/checker.cpp index e2c430dc2..f130a965f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -61,18 +61,6 @@ gb_internal void scope_reserve(Scope *scope, isize capacity) { } } -gb_internal i32 is_scope_an_ancestor(Scope *parent, Scope *child) { - i32 i = 0; - while (child != nullptr) { - if (parent == child) { - return i; - } - child = child->parent; - i++; - } - return -1; -} - gb_internal void entity_graph_node_set_destroy(EntityGraphNodeSet *s) { if (s->hashes.data != nullptr) { ptr_set_destroy(s); @@ -86,9 +74,9 @@ gb_internal void entity_graph_node_set_add(EntityGraphNodeSet *s, EntityGraphNod ptr_set_add(s, n); } -gb_internal bool entity_graph_node_set_exists(EntityGraphNodeSet *s, EntityGraphNode *n) { - return ptr_set_exists(s, n); -} +// gb_internal bool entity_graph_node_set_exists(EntityGraphNodeSet *s, EntityGraphNode *n) { +// return ptr_set_exists(s, n); +// } gb_internal void entity_graph_node_set_remove(EntityGraphNodeSet *s, EntityGraphNode *n) { ptr_set_remove(s, n); @@ -139,13 +127,13 @@ gb_internal void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNod ptr_set_add(s, n); } -gb_internal bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) { - return ptr_set_exists(s, n); -} +// gb_internal bool import_graph_node_set_exists(ImportGraphNodeSet *s, ImportGraphNode *n) { +// return ptr_set_exists(s, n); +// } -gb_internal void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) { - ptr_set_remove(s, n); -} +// gb_internal void import_graph_node_set_remove(ImportGraphNodeSet *s, ImportGraphNode *n) { +// ptr_set_remove(s, n); +// } gb_internal ImportGraphNode *import_graph_node_create(gbAllocator a, AstPackage *pkg) { ImportGraphNode *n = gb_alloc_item(a, ImportGraphNode); @@ -186,15 +174,6 @@ gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j y->index = i; } -gb_internal GB_COMPARE_PROC(ast_node_cmp) { - Ast *x = *cast(Ast **)a; - Ast *y = *cast(Ast **)b; - Token i = ast_token(x); - Token j = ast_token(y); - return token_pos_cmp(i.pos, j.pos); -} - - @@ -213,27 +192,27 @@ gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { return d; } -gb_internal void destroy_declaration_info(DeclInfo *d) { - ptr_set_destroy(&d->deps); - array_free(&d->labels); -} +// gb_internal void destroy_declaration_info(DeclInfo *d) { +// ptr_set_destroy(&d->deps); +// array_free(&d->labels); +// } -gb_internal bool decl_info_has_init(DeclInfo *d) { - if (d->init_expr != nullptr) { - return true; - } - if (d->proc_lit != nullptr) { - switch (d->proc_lit->kind) { - case_ast_node(pl, ProcLit, d->proc_lit); - if (pl->body != nullptr) { - return true; - } - case_end; - } - } +// gb_internal bool decl_info_has_init(DeclInfo *d) { +// if (d->init_expr != nullptr) { +// return true; +// } +// if (d->proc_lit != nullptr) { +// switch (d->proc_lit->kind) { +// case_ast_node(pl, ProcLit, d->proc_lit); +// if (pl->body != nullptr) { +// return true; +// } +// case_end; +// } +// } - return false; -} +// return false; +// } @@ -528,11 +507,6 @@ struct VettedEntity { Entity *entity; Entity *other; }; -gb_internal void init_vetted_entity(VettedEntity *ve, VettedEntityKind kind, Entity *entity, Entity *other=nullptr) { - ve->kind = kind; - ve->entity = entity; - ve->other = other; -} gb_internal GB_COMPARE_PROC(vetted_entity_variable_pos_cmp) { @@ -1144,7 +1118,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { - i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions; + i->allow_identifier_uses = false; if (i->allow_identifier_uses) { array_init(&i->identifier_uses, a); } @@ -1226,13 +1200,10 @@ gb_internal CheckerContext make_checker_context(Checker *c) { ctx.type_path = new_checker_type_path(); ctx.type_level = 0; - ctx.poly_path = new_checker_poly_path(); - ctx.poly_level = 0; return ctx; } gb_internal void destroy_checker_context(CheckerContext *ctx) { destroy_checker_type_path(ctx->type_path); - destroy_checker_poly_path(ctx->poly_path); } gb_internal void add_curr_ast_file(CheckerContext *ctx, AstFile *file) { @@ -1348,17 +1319,17 @@ gb_internal DeclInfo *decl_info_of_entity(Entity *e) { return nullptr; } -gb_internal DeclInfo *decl_info_of_ident(Ast *ident) { - return decl_info_of_entity(entity_of_node(ident)); -} +// gb_internal DeclInfo *decl_info_of_ident(Ast *ident) { +// return decl_info_of_entity(entity_of_node(ident)); +// } -gb_internal AstFile *ast_file_of_filename(CheckerInfo *i, String filename) { - AstFile **found = string_map_get(&i->files, filename); - if (found != nullptr) { - return *found; - } - return nullptr; -} +// gb_internal AstFile *ast_file_of_filename(CheckerInfo *i, String filename) { +// AstFile **found = string_map_get(&i->files, filename); +// if (found != nullptr) { +// return *found; +// } +// return nullptr; +// } gb_internal ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { if (c->untyped != nullptr) { ExprInfo **found = map_get(c->untyped, expr); @@ -2684,32 +2655,6 @@ gb_internal Entity *check_type_path_pop(CheckerContext *c) { } -gb_internal CheckerPolyPath *new_checker_poly_path(void) { - gbAllocator a = heap_allocator(); - auto *pp = gb_alloc_item(a, CheckerPolyPath); - array_init(pp, a, 0, 16); - return pp; -} - -gb_internal void destroy_checker_poly_path(CheckerPolyPath *pp) { - array_free(pp); - gb_free(heap_allocator(), pp); -} - - -gb_internal void check_poly_path_push(CheckerContext *c, Type *t) { - GB_ASSERT(c->poly_path != nullptr); - GB_ASSERT(t != nullptr); - GB_ASSERT(is_type_polymorphic(t)); - array_add(c->poly_path, t); -} - -gb_internal Type *check_poly_path_pop(CheckerContext *c) { - GB_ASSERT(c->poly_path != nullptr); - return array_pop(c->poly_path); -} - - gb_internal Array proc_group_entities(CheckerContext *c, Operand o) { Array procs = {}; @@ -2878,13 +2823,6 @@ gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) return ev; } -gb_internal Type *check_decl_attribute_type(CheckerContext *c, Ast *value) { - if (value != nullptr) { - return check_type(c, value); - } - return nullptr; -} - #define ATTRIBUTE_USER_TAG_NAME "tag" diff --git a/src/checker.hpp b/src/checker.hpp index e1efd5b89..58f6a027c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -397,8 +397,6 @@ struct CheckerContext { CheckerTypePath *type_path; isize type_level; // TODO(bill): Actually handle correctly - CheckerPolyPath *poly_path; - isize poly_level; // TODO(bill): Actually handle correctly UntypedExprInfoMap *untyped; @@ -489,12 +487,6 @@ gb_internal void destroy_checker_type_path(CheckerTypePath *tp); gb_internal void check_type_path_push(CheckerContext *c, Entity *e); gb_internal Entity *check_type_path_pop (CheckerContext *c); -gb_internal CheckerPolyPath *new_checker_poly_path(); -gb_internal void destroy_checker_poly_path(CheckerPolyPath *); - -gb_internal void check_poly_path_push(CheckerContext *c, Type *t); -gb_internal Type *check_poly_path_pop (CheckerContext *c); - gb_internal void init_core_context(Checker *c); gb_internal void init_mem_allocator(Checker *c); diff --git a/src/common.cpp b/src/common.cpp index 09203e633..3624446f1 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -50,6 +50,10 @@ gb_internal void debugf(char const *fmt, ...); #include "string.cpp" #include "range_cache.cpp" +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4505) +#endif gb_internal gb_inline bool is_power_of_two(i64 x) { if (x <= 0) { @@ -900,3 +904,8 @@ gb_internal Slice did_you_mean_results(DidYouMeanAnswers *d) } return slice_array(d->distances, 0, count); } + + +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif \ No newline at end of file diff --git a/src/docs.cpp b/src/docs.cpp index 33b1e8361..b1efa2b46 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -85,15 +85,6 @@ gb_internal void print_doc_line(i32 indent, char const *fmt, ...) { va_end(va); gb_printf("\n"); } -gb_internal void print_doc_line_no_newline(i32 indent, char const *fmt, ...) { - while (indent --> 0) { - gb_printf("\t"); - } - va_list va; - va_start(va, fmt); - gb_printf_va(fmt, va); - va_end(va); -} gb_internal void print_doc_line_no_newline(i32 indent, String const &data) { while (indent --> 0) { gb_printf("\t"); diff --git a/src/entity.cpp b/src/entity.cpp index 6a3a69950..0605a293a 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -404,14 +404,6 @@ gb_internal Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *typ return entity; } - -gb_internal Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) { - Entity *entity = alloc_entity(Entity_Builtin, scope, token, type); - entity->Builtin.id = id; - entity->state = EntityState_Resolved; - return entity; -} - gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type, String path, String name, Scope *import_scope) { Entity *entity = alloc_entity(Entity_ImportName, scope, token, type); diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 453909a15..f4c85505d 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -15,16 +15,6 @@ struct Quaternion256 { f64 imag, jmag, kmag, real; }; -gb_internal Quaternion256 quaternion256_inverse(Quaternion256 x) { - f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag); - x.real = +x.real * invmag2; - x.imag = -x.imag * invmag2; - x.jmag = -x.jmag * invmag2; - x.kmag = -x.kmag * invmag2; - return x; -} - - enum ExactValueKind { ExactValue_Invalid = 0, @@ -453,44 +443,44 @@ gb_internal ExactValue exact_value_kmag(ExactValue v) { return r; } -gb_internal ExactValue exact_value_make_imag(ExactValue v) { - switch (v.kind) { - case ExactValue_Integer: - return exact_value_complex(0, exact_value_to_float(v).value_float); - case ExactValue_Float: - return exact_value_complex(0, v.value_float); - default: - GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); - } - ExactValue r = {ExactValue_Invalid}; - return r; -} - -gb_internal ExactValue exact_value_make_jmag(ExactValue v) { - switch (v.kind) { - case ExactValue_Integer: - return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0); - case ExactValue_Float: - return exact_value_quaternion(0, 0, v.value_float, 0); - default: - GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); - } - ExactValue r = {ExactValue_Invalid}; - return r; -} - -gb_internal ExactValue exact_value_make_kmag(ExactValue v) { - switch (v.kind) { - case ExactValue_Integer: - return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float); - case ExactValue_Float: - return exact_value_quaternion(0, 0, 0, v.value_float); - default: - GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); - } - ExactValue r = {ExactValue_Invalid}; - return r; -} +// gb_internal ExactValue exact_value_make_imag(ExactValue v) { +// switch (v.kind) { +// case ExactValue_Integer: +// return exact_value_complex(0, exact_value_to_float(v).value_float); +// case ExactValue_Float: +// return exact_value_complex(0, v.value_float); +// default: +// GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); +// } +// ExactValue r = {ExactValue_Invalid}; +// return r; +// } + +// gb_internal ExactValue exact_value_make_jmag(ExactValue v) { +// switch (v.kind) { +// case ExactValue_Integer: +// return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0); +// case ExactValue_Float: +// return exact_value_quaternion(0, 0, v.value_float, 0); +// default: +// GB_PANIC("Expected an integer or float type for 'exact_value_make_jmag'"); +// } +// ExactValue r = {ExactValue_Invalid}; +// return r; +// } + +// gb_internal ExactValue exact_value_make_kmag(ExactValue v) { +// switch (v.kind) { +// case ExactValue_Integer: +// return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float); +// case ExactValue_Float: +// return exact_value_quaternion(0, 0, 0, v.value_float); +// default: +// GB_PANIC("Expected an integer or float type for 'exact_value_make_kmag'"); +// } +// ExactValue r = {ExactValue_Invalid}; +// return r; +// } gb_internal i64 exact_value_to_i64(ExactValue v) { v = exact_value_to_integer(v); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ca4b3b683..c5bc96eb9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -605,11 +605,11 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { return {p->value, p->type}; } -gb_internal void lb_debug_print(lbProcedure *p, String const &str) { - auto args = array_make(heap_allocator(), 1); - args[0] = lb_const_string(p->module, str); - lb_emit_runtime_call(p, "print_string", args); -} +// gb_internal void lb_debug_print(lbProcedure *p, String const &str) { +// auto args = array_make(heap_allocator(), 1); +// args[0] = lb_const_string(p->module, str); +// lb_emit_runtime_call(p, "print_string", args); +// } gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) { GB_ASSERT(build_context.use_static_map_calls); diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 849416579..55c4370a2 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -14,12 +14,6 @@ gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef va } } -gb_internal LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) { - if (node == nullptr) { - return nullptr; - } - return lb_get_llvm_metadata(m, node->file()); -} gb_internal LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) { GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name)); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index f30038da8..e5aa95f10 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -272,12 +272,6 @@ gb_internal lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) gb_internal LLVMValueRef llvm_zero(lbModule *m) { return LLVMConstInt(lb_type(m, t_int), 0, false); } -gb_internal LLVMValueRef llvm_zero32(lbModule *m) { - return LLVMConstInt(lb_type(m, t_i32), 0, false); -} -gb_internal LLVMValueRef llvm_one(lbModule *m) { - return LLVMConstInt(lb_type(m, t_i32), 1, false); -} gb_internal LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const *name) { LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); @@ -874,14 +868,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { lb_emit_store(p, addr.addr, value); } -gb_internal void lb_const_store(lbValue ptr, lbValue value) { - GB_ASSERT(lb_is_const(ptr)); - GB_ASSERT(lb_is_const(value)); - GB_ASSERT(is_type_pointer(ptr.type)); - LLVMSetInitializer(ptr.value, value.value); -} - - gb_internal bool lb_is_type_proc_recursive(Type *t) { for (;;) { if (t == nullptr) { @@ -1327,21 +1313,6 @@ gb_internal void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src)); } -gb_internal LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { - switch (alignment) { - case 1: - return LLVMArrayType(lb_type(m, t_u8), 0); - case 2: - return LLVMArrayType(lb_type(m, t_u16), 0); - case 4: - return LLVMArrayType(lb_type(m, t_u32), 0); - case 8: - return LLVMArrayType(lb_type(m, t_u64), 0); - default: case 16: - return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0); - } -} - gb_internal String lb_mangle_name(lbModule *m, Entity *e) { String name = e->token.string; @@ -2202,9 +2173,6 @@ gb_internal void lb_add_member(lbModule *m, String const &name, lbValue val) { string_map_set(&m->members, name, val); } } -gb_internal void lb_add_member(lbModule *m, StringHashKey const &key, lbValue val) { - string_map_set(&m->members, key, val); -} gb_internal void lb_add_procedure_value(lbModule *m, lbProcedure *p) { if (p->entity != nullptr) { map_set(&m->procedure_values, p->value, p->entity); @@ -2493,42 +2461,6 @@ gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) return res; } -gb_internal lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef data = LLVMConstStringInContext(m->ctx, - cast(char const *)str.text, - cast(unsigned)str.len, - false); - - - char *name = nullptr; - { - isize max_len = 7+8+1; - name = gb_alloc_array(permanent_allocator(), char, max_len); - u32 id = m->gen->global_array_index.fetch_add(1); - isize len = gb_snprintf(name, max_len, "csbs$%x", id); - len -= 1; - } - LLVMTypeRef type = LLVMTypeOf(data); - LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); - LLVMSetInitializer(global_data, data); - lb_make_global_private_const(global_data); - LLVMSetAlignment(global_data, 1); - - LLVMValueRef ptr = nullptr; - if (str.len != 0) { - ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); - } else { - ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); - } - LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), str.len, true); - LLVMValueRef values[2] = {ptr, len}; - - lbValue res = {}; - res.value = llvm_const_named_struct(m, t_u8_slice, values, 2); - res.type = t_u8_slice; - return res; -} gb_internal lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) { GB_ASSERT(is_type_slice(slice_type)); LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 533264e62..fd6d94361 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -37,16 +37,16 @@ gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i3 gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level); gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level); -gb_internal LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) { - lbModule *m = cast(lbModule *)user_data; - if (m == nullptr) { - return false; - } - if (value == nullptr) { - return false; - } - return LLVMIsAAllocaInst(value) != nullptr; -} +// gb_internal LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) { +// lbModule *m = cast(lbModule *)user_data; +// if (m == nullptr) { +// return false; +// } +// if (value == nullptr) { +// return false; +// } +// return LLVMIsAAllocaInst(value) != nullptr; +// } #if LLVM_VERSION_MAJOR < 12 diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 0789fb2c1..384d29ca7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -383,46 +383,46 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name } -gb_internal lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) { - lbParamPasskind kind = lbParamPass_Value; - - if (e != nullptr && !are_types_identical(abi_type, e->type)) { - if (is_type_pointer(abi_type)) { - GB_ASSERT(e->kind == Entity_Variable); - Type *av = core_type(type_deref(abi_type)); - if (are_types_identical(av, core_type(e->type))) { - kind = lbParamPass_Pointer; - if (e->flags&EntityFlag_Value) { - kind = lbParamPass_ConstRef; - } - } else { - kind = lbParamPass_BitCast; - } - } else if (is_type_integer(abi_type)) { - kind = lbParamPass_Integer; - } else if (abi_type == t_llvm_bool) { - kind = lbParamPass_Value; - } else if (is_type_boolean(abi_type)) { - kind = lbParamPass_Integer; - } else if (is_type_simd_vector(abi_type)) { - kind = lbParamPass_BitCast; - } else if (is_type_float(abi_type)) { - kind = lbParamPass_BitCast; - } else if (is_type_tuple(abi_type)) { - kind = lbParamPass_Tuple; - } else if (is_type_proc(abi_type)) { - kind = lbParamPass_Value; - } else { - GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); - } - } - - if (kind_) *kind_ = kind; - lbValue res = {}; - res.value = LLVMGetParam(p->value, cast(unsigned)index); - res.type = abi_type; - return res; -} +// gb_internal lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) { +// lbParamPasskind kind = lbParamPass_Value; + +// if (e != nullptr && !are_types_identical(abi_type, e->type)) { +// if (is_type_pointer(abi_type)) { +// GB_ASSERT(e->kind == Entity_Variable); +// Type *av = core_type(type_deref(abi_type)); +// if (are_types_identical(av, core_type(e->type))) { +// kind = lbParamPass_Pointer; +// if (e->flags&EntityFlag_Value) { +// kind = lbParamPass_ConstRef; +// } +// } else { +// kind = lbParamPass_BitCast; +// } +// } else if (is_type_integer(abi_type)) { +// kind = lbParamPass_Integer; +// } else if (abi_type == t_llvm_bool) { +// kind = lbParamPass_Value; +// } else if (is_type_boolean(abi_type)) { +// kind = lbParamPass_Integer; +// } else if (is_type_simd_vector(abi_type)) { +// kind = lbParamPass_BitCast; +// } else if (is_type_float(abi_type)) { +// kind = lbParamPass_BitCast; +// } else if (is_type_tuple(abi_type)) { +// kind = lbParamPass_Tuple; +// } else if (is_type_proc(abi_type)) { +// kind = lbParamPass_Value; +// } else { +// GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); +// } +// } + +// if (kind_) *kind_ = kind; +// lbValue res = {}; +// res.value = LLVMGetParam(p->value, cast(unsigned)index); +// res.type = abi_type; +// return res; +// } @@ -1165,14 +1165,6 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c return result; } -gb_internal LLVMValueRef llvm_splat_float(i64 count, LLVMTypeRef type, f64 value) { - LLVMValueRef v = LLVMConstReal(type, value); - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count); - for (i64 i = 0; i < count; i++) { - values[i] = v; - } - return LLVMConstVector(values, cast(unsigned)count); -} gb_internal LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) { LLVMValueRef v = LLVMConstInt(type, value, is_signed); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 66c422071..6400a8a9d 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -378,16 +378,6 @@ gb_internal lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue return lb_emit_ptr_offset(p, elems_ptr, data_index); } -gb_internal void lb_map_kvh_data_static(lbProcedure *p, lbValue map_value, lbValue *ks_, lbValue *vs_, lbValue *hs_) { - lbValue capacity = lb_map_cap(p, map_value); - lbValue ks = lb_map_data_uintptr(p, map_value); - lbValue vs = {}; - lbValue hs = {}; - if (ks_) *ks_ = ks; - if (vs_) *vs_ = vs; - if (hs_) *hs_ = hs; -} - gb_internal lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) { // N :: size_of(uintptr)*8 - 1 // (hash != 0) & (hash>>N == 0) diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 94b900278..dbed32b82 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -599,14 +599,6 @@ gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) } -gb_internal lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x) { - GB_ASSERT(is_type_bit_set(x.type)); - Type *underlying = bit_set_to_int(x.type); - lbValue card = lb_emit_count_ones(p, x, underlying); - return lb_emit_conv(p, card, t_int); -} - - gb_internal lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { GB_ASSERT(is_type_tuple(type)); lbModule *m = p->module; @@ -1493,10 +1485,6 @@ gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) { GB_ASSERT(is_type_dynamic_array(da.type)); return lb_emit_struct_ev(p, da, 2); } -gb_internal lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) { - GB_ASSERT(is_type_dynamic_array(da.type)); - return lb_emit_struct_ev(p, da, 3); -} gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value) { GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type)); diff --git a/src/main.cpp b/src/main.cpp index 614130bb6..c7250aa8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,7 +3,14 @@ #include "common.cpp" #include "timings.cpp" #include "tokenizer.cpp" +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4505) +#endif #include "big_int.cpp" +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif #include "exact_value.cpp" #include "build_settings.cpp" @@ -58,7 +65,6 @@ gb_global Timings global_timings = {0}; #endif #endif -#include "query_data.cpp" #include "bug_report.cpp" // NOTE(bill): 'name' is used in debugging and profiling modes @@ -573,7 +579,6 @@ gb_internal void usage(String argv0) { print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "check parse, and type check a directory of .odin files"); - print_usage_line(1, "query parse, type check, and output a .json file containing information about the program"); print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package"); print_usage_line(1, "doc generate documentation on a directory of .odin files"); @@ -817,12 +822,6 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_UseStaticMapCalls, str_lit("use-static-map-calls"), BuildFlagParam_None, Command__does_check); - - add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query); - add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query); - add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query); - - add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc); @@ -1445,39 +1444,6 @@ gb_internal bool parse_build_flags(Array args) { build_context.strict_style_init_only = true; break; } - case BuildFlag_Compact: { - if (!build_context.query_data_set_settings.ok) { - gb_printf_err("Invalid use of -compact flag, only allowed with 'odin query'\n"); - bad_flags = true; - } else { - build_context.query_data_set_settings.compact = true; - } - break; - } - case BuildFlag_GlobalDefinitions: { - if (!build_context.query_data_set_settings.ok) { - gb_printf_err("Invalid use of -global-definitions flag, only allowed with 'odin query'\n"); - bad_flags = true; - } else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) { - gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n"); - bad_flags = true; - } else { - build_context.query_data_set_settings.kind = QueryDataSet_GlobalDefinitions; - } - break; - } - case BuildFlag_GoToDefinitions: { - if (!build_context.query_data_set_settings.ok) { - gb_printf_err("Invalid use of -go-to-definitions flag, only allowed with 'odin query'\n"); - bad_flags = true; - } else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) { - gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n"); - bad_flags = true; - } else { - build_context.query_data_set_settings.kind = QueryDataSet_GoToDefinitions; - } - break; - } case BuildFlag_Short: build_context.cmd_doc_flags |= CmdDocFlag_Short; break; @@ -1638,16 +1604,6 @@ gb_internal bool parse_build_flags(Array args) { gb_printf_err("`-export-timings:` requires `-show-timings` or `-show-more-timings` to be present\n"); bad_flags = true; } - - if (build_context.query_data_set_settings.ok) { - if (build_context.query_data_set_settings.kind == QueryDataSet_Invalid) { - gb_printf_err("'odin query' requires a flag determining the kind of query data set to be returned\n"); - gb_printf_err("\t-global-definitions : outputs a JSON file of global definitions\n"); - gb_printf_err("\t-go-to-definitions : outputs a OGTD binary file of go to definitions for identifiers within an Odin project\n"); - bad_flags = true; - } - } - return !bad_flags; } @@ -1931,8 +1887,6 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); } else if (command == "test") { print_usage_line(1, "test Build ands runs procedures with the attribute @(test) in the initial package"); - } else if (command == "query") { - print_usage_line(1, "query [experimental] Parse, type check, and output a .json file containing information about the program"); } else if (command == "doc") { print_usage_line(1, "doc generate documentation from a directory of .odin files"); print_usage_line(2, "Examples:"); @@ -2627,15 +2581,6 @@ int main(int arg_count, char const **arg_ptr) { build_context.command_kind = Command_strip_semicolon; build_context.no_output_files = true; init_filename = args[2]; - } else if (command == "query") { - if (args.count < 3) { - usage(args[0]); - return 1; - } - build_context.command_kind = Command_query; - build_context.no_output_files = true; - build_context.query_data_set_settings.ok = true; - init_filename = args[2]; } else if (command == "doc") { if (args.count < 3) { usage(args[0]); @@ -2824,12 +2769,8 @@ int main(int arg_count, char const **arg_ptr) { print_show_unused(checker); } - if (build_context.query_data_set_settings.ok) { - generate_and_print_query_data(checker, &global_timings); - } else { - if (build_context.show_timings) { - show_timings(checker, &global_timings); - } + if (build_context.show_timings) { + show_timings(checker, &global_timings); } if (global_error_collector.count != 0) { diff --git a/src/parser.cpp b/src/parser.cpp index 1606f5b47..2ccdac7fa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -237,9 +237,6 @@ gb_internal Ast *clone_ast(Ast *node) { case Ast_ExprStmt: n->ExprStmt.expr = clone_ast(n->ExprStmt.expr); break; - case Ast_TagStmt: - n->TagStmt.stmt = clone_ast(n->TagStmt.stmt); - break; case Ast_AssignStmt: n->AssignStmt.lhs = clone_ast_array(n->AssignStmt.lhs); n->AssignStmt.rhs = clone_ast_array(n->AssignStmt.rhs); @@ -497,14 +494,6 @@ gb_internal Ast *ast_tag_expr(AstFile *f, Token token, Token name, Ast *expr) { return result; } -gb_internal Ast *ast_tag_stmt(AstFile *f, Token token, Token name, Ast *stmt) { - Ast *result = alloc_ast_node(f, Ast_TagStmt); - result->TagStmt.token = token; - result->TagStmt.name = name; - result->TagStmt.stmt = stmt; - return result; -} - gb_internal Ast *ast_unary_expr(AstFile *f, Token op, Ast *expr) { Ast *result = alloc_ast_node(f, Ast_UnaryExpr); result->UnaryExpr.op = op; @@ -1308,16 +1297,6 @@ gb_internal Token advance_token(AstFile *f) { return prev; } -gb_internal bool peek_token_kind(AstFile *f, TokenKind kind) { - for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) { - Token tok = f->tokens[i]; - if (kind != Token_Comment && tok.kind == Token_Comment) { - continue; - } - return tok.kind == kind; - } - return false; -} gb_internal Token peek_token(AstFile *f) { for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) { @@ -1440,17 +1419,6 @@ gb_internal Token expect_operator(AstFile *f) { return prev; } -gb_internal Token expect_keyword(AstFile *f) { - Token prev = f->curr_token; - if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) { - String p = token_to_string(prev); - syntax_error(f->curr_token, "Expected a keyword, got '%.*s'", - LIT(p)); - } - advance_token(f); - return prev; -} - gb_internal bool allow_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind == kind) { @@ -1957,10 +1925,6 @@ gb_internal bool ast_on_same_line(Token const &x, Ast *yp) { return x.pos.line == y.pos.line; } -gb_internal bool ast_on_same_line(Ast *x, Ast *y) { - return ast_on_same_line(ast_token(x), y); -} - gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) { Ast *expr = parse_unary_expr(f, false); Ast *e = strip_or_return_expr(expr); diff --git a/src/parser.hpp b/src/parser.hpp index a2d2c038e..f7b3e51ae 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -457,11 +457,6 @@ AST_KIND(_StmtBegin, "", bool) \ AST_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \ AST_KIND(EmptyStmt, "empty statement", struct { Token token; }) \ AST_KIND(ExprStmt, "expression statement", struct { Ast *expr; } ) \ - AST_KIND(TagStmt, "tag statement", struct { \ - Token token; \ - Token name; \ - Ast * stmt; \ - }) \ AST_KIND(AssignStmt, "assign statement", struct { \ Token op; \ Slice lhs, rhs; \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 19a525e2e..fb7f0c9c2 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -53,7 +53,6 @@ gb_internal Token ast_token(Ast *node) { case Ast_BadStmt: return node->BadStmt.begin; case Ast_EmptyStmt: return node->EmptyStmt.token; case Ast_ExprStmt: return ast_token(node->ExprStmt.expr); - case Ast_TagStmt: return node->TagStmt.token; case Ast_AssignStmt: return node->AssignStmt.op; case Ast_BlockStmt: return node->BlockStmt.open; case Ast_IfStmt: return node->IfStmt.token; @@ -197,7 +196,6 @@ Token ast_end_token(Ast *node) { case Ast_BadStmt: return node->BadStmt.end; case Ast_EmptyStmt: return node->EmptyStmt.token; case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr); - case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt); case Ast_AssignStmt: if (node->AssignStmt.rhs.count > 0) { return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]); diff --git a/src/query_data.cpp b/src/query_data.cpp deleted file mode 100644 index 86487a058..000000000 --- a/src/query_data.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -struct QueryValue; -struct QueryValuePair; - -gb_global gbAllocator query_value_allocator = {}; - -enum QueryKind { - Query_Invalid, - Query_String, - Query_Boolean, - Query_Integer, - Query_Float, - Query_Array, - Query_Map, -}; - -struct QueryValuePair { - String key; - QueryValue *value; -}; - - -struct QueryValue { - QueryKind kind; - bool packed; -}; - -struct QueryValueString : QueryValue { - QueryValueString(String const &v) { - kind = Query_String; - value = v; - packed = false; - } - String value; -}; - -struct QueryValueBoolean : QueryValue { - QueryValueBoolean(bool v) { - kind = Query_Boolean; - value = v; - packed = false; - } - bool value; -}; - -struct QueryValueInteger : QueryValue { - QueryValueInteger(i64 v) { - kind = Query_Integer; - value = v; - packed = false; - } - i64 value; -}; - -struct QueryValueFloat : QueryValue { - QueryValueFloat(f64 v) { - kind = Query_Float; - value = v; - packed = false; - } - f64 value; -}; - -struct QueryValueArray : QueryValue { - QueryValueArray() { - kind = Query_Array; - array_init(&value, query_value_allocator); - packed = false; - } - QueryValueArray(Array const &v) { - kind = Query_Array; - value = v; - packed = false; - } - Array value; - - void reserve(isize cap) { - array_reserve(&value, cap); - } - void add(QueryValue *v) { - array_add(&value, v); - } - void add(char const *v) { - add(make_string_c(cast(char *)v)); - } - void add(String const &v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueString); - *val = QueryValueString(v); - add(val); - } - void add(bool v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean); - *val = QueryValueBoolean(v); - add(val); - } - void add(i64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueInteger); - *val = QueryValueInteger(v); - add(val); - } - void add(f64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueFloat); - *val = QueryValueFloat(v); - add(val); - } -}; - -struct QueryValueMap : QueryValue { - QueryValueMap() { - kind = Query_Map; - array_init(&value, query_value_allocator); - packed = false; - } - QueryValueMap(Array const &v) { - kind = Query_Map; - value = v; - packed = false; - } - Array value; - - - void reserve(isize cap) { - array_reserve(&value, cap); - } - void add(char const *k, QueryValue *v) { - add(make_string_c(cast(char *)k), v); - } - void add(String const &k, QueryValue *v) { - QueryValuePair kv = {k, v}; - array_add(&value, kv); - } - - void add(char const *k, String const &v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueString); - *val = QueryValueString(v); - add(k, val); - } - void add(char const *k, char const *v) { - add(k, make_string_c(cast(char *)v)); - } - void add(char const *k, bool v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean); - *val = QueryValueBoolean(v); - add(k, val); - } - void add(char const *k, i64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueInteger); - *val = QueryValueInteger(v); - add(k, val); - } - void add(char const *k, f64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueFloat); - *val = QueryValueFloat(v); - add(k, val); - } - void add(String const &k, String const &v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueString); - *val = QueryValueString(v); - add(k, val); - } - void add(String const &k, char const *v) { - add(k, make_string_c(cast(char *)v)); - } - void add(String const &k, bool v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueBoolean); - *val = QueryValueBoolean(v); - add(k, val); - } - void add(String const &k, i64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueInteger); - *val = QueryValueInteger(v); - add(k, val); - } - void add(String const &k, f64 v) { - auto val = gb_alloc_item(query_value_allocator, QueryValueFloat); - *val = QueryValueFloat(v); - add(k, val); - } -}; - - -#define DEF_QUERY_PROC(TYPE, VALUETYPE, NAME) TYPE *NAME(VALUETYPE value) { \ - auto v = gb_alloc_item(query_value_allocator, TYPE); \ - *v = TYPE(value); \ - return v; \ -} -#define DEF_QUERY_PROC0(TYPE, NAME) TYPE *NAME() { \ - auto v = gb_alloc_item(query_value_allocator, TYPE); \ - *v = TYPE(); \ - return v; \ -} - -gb_internal DEF_QUERY_PROC(QueryValueString, String const &, query_value_string); -gb_internal DEF_QUERY_PROC(QueryValueBoolean, bool, query_value_boolean); -gb_internal DEF_QUERY_PROC(QueryValueInteger, i64, query_value_integer); -gb_internal DEF_QUERY_PROC(QueryValueFloat, f64, query_value_float); -gb_internal DEF_QUERY_PROC(QueryValueArray, Array const &, query_value_array); -gb_internal DEF_QUERY_PROC(QueryValueMap, Array const &, query_value_map); -gb_internal DEF_QUERY_PROC0(QueryValueArray, query_value_array); -gb_internal DEF_QUERY_PROC0(QueryValueMap, query_value_map); - -gb_internal isize qprintf(bool format, isize indent, char const *fmt, ...) { - if (format) while (indent --> 0) { - gb_printf("\t"); - } - va_list va; - va_start(va, fmt); - isize res = gb_printf_va(fmt, va); - va_end(va); - return res; -} - -gb_internal bool qv_valid_char(u8 c) { - if (c >= 0x80) { - return false; - } - - switch (c) { - case '\"': - case '\n': - case '\r': - case '\t': - case '\v': - case '\f': - return false; - } - - return true; -} - -gb_internal void print_query_data_as_json(QueryValue *value, bool format = true, isize indent = 0) { - if (value == nullptr) { - gb_printf("null"); - return; - } - switch (value->kind) { - case Query_String: { - auto v = cast(QueryValueString *)value; - String name = v->value; - isize extra = 0; - for (isize i = 0; i < name.len; i++) { - u8 c = name[i]; - if (!qv_valid_char(c)) { - extra += 5; - } - } - - if (extra == 0) { - gb_printf("\"%.*s\"", LIT(name)); - return; - } - - char const hex_table[] = "0123456789ABCDEF"; - isize buf_len = name.len + extra + 2 + 1; - - u8 *buf = gb_alloc_array(temporary_allocator(), u8, buf_len); - - isize j = 0; - - for (isize i = 0; i < name.len; i++) { - u8 c = name[i]; - if (qv_valid_char(c)) { - buf[j+0] = c; - j += 1; - } else if (c == '"') { - buf[j+0] = '\\'; - buf[j+1] = '\"'; - j += 2; - } else { - switch (c) { - case '\n': buf[j+0] = '\\'; buf[j+1] = 'n'; j += 2; break; - case '\r': buf[j+0] = '\\'; buf[j+1] = 'r'; j += 2; break; - case '\t': buf[j+0] = '\\'; buf[j+1] = 't'; j += 2; break; - case '\v': buf[j+0] = '\\'; buf[j+1] = 'v'; j += 2; break; - case '\f': - default: - buf[j+0] = '\\'; - buf[j+1] = hex_table[0]; - buf[j+2] = hex_table[0]; - buf[j+3] = hex_table[c >> 4]; - buf[j+4] = hex_table[c & 0x0f]; - j += 5; - break; - } - } - } - - gb_printf("\"%s\"", buf); - return; - } - case Query_Boolean: { - auto v = cast(QueryValueBoolean *)value; - if (v->value) { - gb_printf("true"); - } else { - gb_printf("false"); - } - return; - } - case Query_Integer: { - auto v = cast(QueryValueInteger *)value; - gb_printf("%lld", cast(long long)v->value); - return; - } - case Query_Float: { - auto v = cast(QueryValueFloat *)value; - gb_printf("%f", v->value); - return; - } - case Query_Array: { - auto v = cast(QueryValueArray *)value; - if (v->value.count > 0) { - bool ff = format && !v->packed; - gb_printf("["); - if (ff) gb_printf("\n"); - for_array(i, v->value) { - qprintf(ff, indent+1, ""); - print_query_data_as_json(v->value[i], ff, indent+1); - if (i < v->value.count-1) { - gb_printf(","); - if (!ff && format) { - gb_printf(" "); - } - } - if (ff) gb_printf("\n"); - } - qprintf(ff, indent, "]"); - } else { - gb_printf("[]"); - } - return; - } - case Query_Map: { - auto v = cast(QueryValueMap *)value; - if (v->value.count > 0) { - bool ff = format && !v->packed; - gb_printf("{"); - if (ff) gb_printf("\n"); - for_array(i, v->value) { - auto kv = v->value[i]; - qprintf(ff, indent+1, "\"%.*s\":", LIT(kv.key)); - if (format) gb_printf(" "); - print_query_data_as_json(kv.value, ff, indent+1); - if (i < v->value.count-1) { - gb_printf(","); - if (!ff && format) { - gb_printf(" "); - } - } - if (ff) gb_printf("\n"); - } - qprintf(ff, indent, "}"); - } else { - gb_printf("{}"); - } - return; - } - } -} - - - -gb_internal int query_data_package_compare(void const *a, void const *b) { - AstPackage *x = *cast(AstPackage *const *)a; - AstPackage *y = *cast(AstPackage *const *)b; - - if (x == y) { - return 0; - } - - if (x != nullptr && y != nullptr) { - return string_compare(x->name, y->name); - } else if (x != nullptr && y == nullptr) { - return -1; - } else if (x == nullptr && y != nullptr) { - return +1; - } - return 0; -} - -gb_internal int query_data_definition_compare(void const *a, void const *b) { - Entity *x = *cast(Entity *const *)a; - Entity *y = *cast(Entity *const *)b; - - if (x == y) { - return 0; - } else if (x != nullptr && y == nullptr) { - return -1; - } else if (x == nullptr && y != nullptr) { - return +1; - } - - if (x->pkg != y->pkg) { - i32 res = query_data_package_compare(&x->pkg, &y->pkg); - if (res != 0) { - return res; - } - } - - return string_compare(x->token.string, y->token.string); -} - -gb_internal int entity_name_compare(void const *a, void const *b) { - Entity *x = *cast(Entity *const *)a; - Entity *y = *cast(Entity *const *)b; - if (x == y) { - return 0; - } else if (x != nullptr && y == nullptr) { - return -1; - } else if (x == nullptr && y != nullptr) { - return +1; - } - return string_compare(x->token.string, y->token.string); -} - - -gb_internal void generate_and_print_query_data_global_definitions(Checker *c, Timings *timings); -gb_internal void generate_and_print_query_data_go_to_definitions(Checker *c); - -gb_internal void generate_and_print_query_data(Checker *c, Timings *timings) { - query_value_allocator = heap_allocator(); - switch (build_context.query_data_set_settings.kind) { - case QueryDataSet_GlobalDefinitions: - generate_and_print_query_data_global_definitions(c, timings); - return; - case QueryDataSet_GoToDefinitions: - generate_and_print_query_data_go_to_definitions(c); - return; - } -} - - -gb_internal void generate_and_print_query_data_global_definitions(Checker *c, Timings *timings) { - auto *root = query_value_map(); - - if (global_error_collector.errors.count > 0) { - auto *errors = query_value_array(); - root->add("errors", errors); - for_array(i, global_error_collector.errors) { - String err = string_trim_whitespace(global_error_collector.errors[i]); - errors->add(err); - } - - } - - { // Packages - auto *packages = query_value_array(); - root->add("packages", packages); - - auto sorted_packages = array_make(query_value_allocator, 0, c->info.packages.entries.count); - defer (array_free(&sorted_packages)); - - for (auto const &entry : c->info.packages) { - AstPackage *pkg = entry.value; - if (pkg != nullptr) { - array_add(&sorted_packages, pkg); - } - } - gb_sort_array(sorted_packages.data, sorted_packages.count, query_data_package_compare); - packages->reserve(sorted_packages.count); - - for_array(i, sorted_packages) { - AstPackage *pkg = sorted_packages[i]; - String name = pkg->name; - String fullpath = pkg->fullpath; - - auto *files = query_value_array(); - files->reserve(pkg->files.count); - for_array(j, pkg->files) { - AstFile *f = pkg->files[j]; - files->add(f->fullpath); - } - - auto *package = query_value_map(); - package->reserve(3); - packages->add(package); - - package->add("name", pkg->name); - package->add("fullpath", pkg->fullpath); - package->add("files", files); - } - } - - if (c->info.definitions.count > 0) { - auto *definitions = query_value_array(); - root->add("definitions", definitions); - - auto sorted_definitions = array_make(query_value_allocator, 0, c->info.definitions.count); - defer (array_free(&sorted_definitions)); - - for_array(i, c->info.definitions) { - Entity *e = c->info.definitions[i]; - String name = e->token.string; - if (is_blank_ident(name)) { - continue; - } - if ((e->scope->flags & (ScopeFlag_Pkg|ScopeFlag_File)) == 0) { - continue; - } - if (e->parent_proc_decl != nullptr) { - continue; - } - switch (e->kind) { - case Entity_Builtin: - case Entity_Nil: - case Entity_Label: - continue; - } - if (e->pkg == nullptr) { - continue; - } - if (e->token.pos.line == 0) { - continue; - } - if (e->kind == Entity_Procedure) { - Type *t = base_type(e->type); - if (t->kind != Type_Proc) { - continue; - } - if (t->Proc.is_poly_specialized) { - continue; - } - } - if (e->kind == Entity_TypeName) { - Type *t = base_type(e->type); - if (t->kind == Type_Struct) { - if (t->Struct.is_poly_specialized) { - continue; - } - } - if (t->kind == Type_Union) { - if (t->Union.is_poly_specialized) { - continue; - } - } - } - - array_add(&sorted_definitions, e); - } - - gb_sort_array(sorted_definitions.data, sorted_definitions.count, query_data_definition_compare); - definitions->reserve(sorted_definitions.count); - - for_array(i, sorted_definitions) { - Entity *e = sorted_definitions[i]; - String name = e->token.string; - - auto *def = query_value_map(); - def->reserve(16); - definitions->add(def); - - def->add("package", e->pkg->name); - def->add("name", name); - def->add("filepath", get_file_path_string(e->token.pos.file_id)); - def->add("line", cast(i64)e->token.pos.line); - def->add("column", cast(i64)e->token.pos.column); - def->add("file_offset", cast(i64)e->token.pos.offset); - - switch (e->kind) { - case Entity_Constant: def->add("kind", str_lit("constant")); break; - case Entity_Variable: def->add("kind", str_lit("variable")); break; - case Entity_TypeName: def->add("kind", str_lit("type name")); break; - case Entity_Procedure: def->add("kind", str_lit("procedure")); break; - case Entity_ProcGroup: def->add("kind", str_lit("procedure group")); break; - case Entity_ImportName: def->add("kind", str_lit("import name")); break; - case Entity_LibraryName: def->add("kind", str_lit("library name")); break; - default: GB_PANIC("Invalid entity kind to be added"); - } - - - if (e->type != nullptr && e->type != t_invalid) { - Type *t = e->type; - Type *bt = t; - - switch (e->kind) { - case Entity_TypeName: - if (!e->TypeName.is_type_alias) { - bt = base_type(t); - } - break; - } - - { - gbString str = type_to_string(t); - String type_str = make_string(cast(u8 *)str, gb_string_length(str)); - def->add("type", type_str); - } - if (t != bt) { - gbString str = type_to_string(bt); - String type_str = make_string(cast(u8 *)str, gb_string_length(str)); - def->add("base_type", type_str); - } - { - String type_kind = {}; - Type *bt = base_type(t); - switch (bt->kind) { - case Type_Pointer: type_kind = str_lit("pointer"); break; - case Type_Array: type_kind = str_lit("array"); break; - case Type_Slice: type_kind = str_lit("slice"); break; - case Type_DynamicArray: type_kind = str_lit("dynamic array"); break; - case Type_Map: type_kind = str_lit("map"); break; - case Type_Struct: type_kind = str_lit("struct"); break; - case Type_Union: type_kind = str_lit("union"); break; - case Type_Enum: type_kind = str_lit("enum"); break; - case Type_Proc: type_kind = str_lit("procedure"); break; - case Type_BitSet: type_kind = str_lit("bit set"); break; - case Type_SimdVector: type_kind = str_lit("simd vector"); break; - - case Type_Generic: - case Type_Tuple: - GB_PANIC("Invalid definition type"); - break; - } - if (type_kind.len > 0) { - def->add("type_kind", type_kind); - } - } - } - - if (e->kind == Entity_TypeName) { - def->add("size", type_size_of(e->type)); - def->add("align", type_align_of(e->type)); - - - if (is_type_struct(e->type)) { - auto *data = query_value_map(); - data->reserve(6); - - def->add("data", data); - - Type *t = base_type(e->type); - GB_ASSERT(t->kind == Type_Struct); - - if (t->Struct.is_polymorphic) { - data->add("polymorphic", cast(bool)t->Struct.is_polymorphic); - } - if (t->Struct.is_poly_specialized) { - data->add("polymorphic_specialized", cast(bool)t->Struct.is_poly_specialized); - } - if (t->Struct.is_packed) { - data->add("packed", cast(bool)t->Struct.is_packed); - } - if (t->Struct.is_raw_union) { - data->add("raw_union", cast(bool)t->Struct.is_raw_union); - } - - auto *fields = query_value_array(); - data->add("fields", fields); - fields->reserve(t->Struct.fields.count); - fields->packed = true; - - for_array(j, t->Struct.fields) { - Entity *e = t->Struct.fields[j]; - String name = e->token.string; - if (is_blank_ident(name)) { - continue; - } - - fields->add(name); - } - } else if (is_type_union(e->type)) { - auto *data = query_value_map(); - data->reserve(4); - - def->add("data", data); - Type *t = base_type(e->type); - GB_ASSERT(t->kind == Type_Union); - - if (t->Union.is_polymorphic) { - data->add("polymorphic", cast(bool)t->Union.is_polymorphic); - } - if (t->Union.is_poly_specialized) { - data->add("polymorphic_specialized", cast(bool)t->Union.is_poly_specialized); - } - - auto *variants = query_value_array(); - variants->reserve(t->Union.variants.count); - data->add("variants", variants); - - for_array(j, t->Union.variants) { - Type *vt = t->Union.variants[j]; - - gbString str = type_to_string(vt); - String type_str = make_string(cast(u8 *)str, gb_string_length(str)); - variants->add(type_str); - } - } - } - - if (e->kind == Entity_Procedure) { - Type *t = base_type(e->type); - GB_ASSERT(t->kind == Type_Proc); - - bool is_polymorphic = t->Proc.is_polymorphic; - bool is_poly_specialized = t->Proc.is_poly_specialized; - bool ok = is_polymorphic || is_poly_specialized; - if (ok) { - auto *data = query_value_map(); - data->reserve(4); - - def->add("data", data); - if (is_polymorphic) { - data->add("polymorphic", cast(bool)is_polymorphic); - } - if (is_poly_specialized) { - data->add("polymorphic_specialized", cast(bool)is_poly_specialized); - } - } - } - - if (e->kind == Entity_ProcGroup) { - auto *procedures = query_value_array(); - procedures->reserve(e->ProcGroup.entities.count); - - for_array(j, e->ProcGroup.entities) { - Entity *p = e->ProcGroup.entities[j]; - - auto *procedure = query_value_map(); - procedure->reserve(2); - procedure->packed = true; - - procedures->add(procedure); - - procedure->add("package", p->pkg->name); - procedure->add("name", p->token.string); - } - def->add("procedures", procedures); - } - - DeclInfo *di = e->decl_info; - if (di != nullptr) { - if (di->is_using) { - def->add("using", query_value_boolean(true)); - } - } - } - } - - if (build_context.show_timings) { - Timings *t = timings; - timings__stop_current_section(t); - t->total.finish = time_stamp_time_now(); - isize max_len = gb_min(36, t->total.label.len); - for_array(i, t->sections) { - TimeStamp ts = t->sections[i]; - max_len = gb_max(max_len, ts.label.len); - } - t->total_time_seconds = time_stamp_as_s(t->total, t->freq); - - auto *tims = query_value_map(); - tims->reserve(8); - root->add("timings", tims); - tims->add("time_unit", str_lit("s")); - - tims->add(t->total.label, cast(f64)t->total_time_seconds); - - - Parser *p = c->parser; - if (p != nullptr) { - isize lines = p->total_line_count; - isize tokens = p->total_token_count; - isize files = 0; - isize packages = p->packages.count; - isize total_file_size = 0; - for_array(i, p->packages) { - files += p->packages[i]->files.count; - for_array(j, p->packages[i]->files) { - AstFile *file = p->packages[i]->files[j]; - total_file_size += file->tokenizer.end - file->tokenizer.start; - } - } - - tims->add("total_lines", cast(i64)lines); - tims->add("total_tokens", cast(i64)tokens); - tims->add("total_files", cast(i64)files); - tims->add("total_packages", cast(i64)packages); - tims->add("total_file_size", cast(i64)total_file_size); - - auto *sections = query_value_map(); - sections->reserve(t->sections.count); - tims->add("sections", sections); - for_array(i, t->sections) { - TimeStamp ts = t->sections[i]; - f64 section_time = time_stamp_as_s(ts, t->freq); - - auto *section = query_value_map(); - section->reserve(2); - sections->add(ts.label, section); - section->add("time", cast(f64)section_time); - section->add("total_fraction", cast(f64)(section_time/t->total_time_seconds)); - } - } - } - - - print_query_data_as_json(root, !build_context.query_data_set_settings.compact); - gb_printf("\n"); -} - - - -template -struct BinaryArray { - u32 offset; // Offset in bytes from the top of the file - u32 length; // Number of elements in array of type T -}; - -template -gb_internal Array binary_array_from_data(BinaryArray ba, void *data) { - Array res = {}; - res.data = cast(T *)(cast(u8 *)data + ba.offset); - res.count = ba.length; - res.capacity = ba.length; - return res; -} - -typedef BinaryArray BinaryString; - -struct GoToDefIdent { - u64 use_offset; // offset of identifier use in bytes from the start of the file that contains it - u32 len; // length in bytes of the identifier - u32 def_file_id; - u64 def_offset; // offset of entity definition in bytes from the start of the file that contains it -}; - -struct GoToDefFile { - u32 id; - BinaryString path; - BinaryArray idents; -}; - -struct GoToDefHeader { - u8 magic[4]; // ogtd (odin-go-to-definitions) - u32 version; // 1 - BinaryArray files; -}; - -struct GoToDefFileMap { - AstFile *f; - u32 id; - Array idents; -}; - - -gb_internal int go_to_def_file_map_compare(void const *a, void const *b) { - GoToDefFileMap const *x = cast(GoToDefFileMap const *)a; - GoToDefFileMap const *y = cast(GoToDefFileMap const *)b; - if (x == y) { - return 0; - } else if (x != nullptr && y == nullptr) { - return -1; - } else if (x == nullptr && y != nullptr) { - return +1; - } - if (x->f->id < y->f->id) { - return -1; - } else if (x->f->id > y->f->id) { - return +1; - } - return 0; -} - -gb_internal int quick_ident_compare(void const *a, void const *b) { - Ast *x = *cast(Ast **)a; - Ast *y = *cast(Ast **)b; - - // NOTE(bill): This assumes that the file is same - if (x->Ident.token.pos.offset < y->Ident.token.pos.offset) { - return -1; - } else if (x->Ident.token.pos.offset > y->Ident.token.pos.offset) { - return +1; - } - return 0; -} - - -gb_internal void generate_and_print_query_data_go_to_definitions(Checker *c) { - GB_ASSERT(c->info.allow_identifier_uses); - - gbAllocator a = query_value_allocator; - - isize file_path_memory_needed = 0; - auto files = array_make(a, 0, c->info.files.entries.count); - for (auto const &entry : c->info.files) { - AstFile *f = entry.value; - file_path_memory_needed += f->fullpath.len+1; // add NUL terminator - - - GoToDefFileMap x = {}; - x.f = f; - array_init(&x.idents, a); - array_add(&files, x); - } - gb_sort_array(files.data, files.count, go_to_def_file_map_compare); - - auto file_id_map_to_index = array_make(a, files[files.count-1].f->id + 1); - for_array(i, file_id_map_to_index) { - file_id_map_to_index[i] = -1; - } - for_array(i, files) { - file_id_map_to_index[files[i].f->id] = i; - } - - - - for_array(i, c->info.identifier_uses) { - Ast *ast = c->info.identifier_uses[i]; - GB_ASSERT(ast->kind == Ast_Ident); - TokenPos pos = ast->Ident.token.pos; - Entity *e = ast->Ident.entity; - if (e == nullptr) { - continue; - } - - - AstFile **use_file_found = string_map_get(&c->info.files, get_file_path_string(pos.file_id)); - GB_ASSERT(use_file_found != nullptr); - AstFile *use_file = *use_file_found; - GB_ASSERT(use_file != nullptr); - - if (e->scope == nullptr) { - GB_ASSERT(e->flags & EntityFlag_Field); - continue; - } - if (e->scope->flags & ScopeFlag_Global) { - continue; - } - - isize idx = file_id_map_to_index[use_file->id]; - if (idx >= 0) { - array_add(&files[idx].idents, ast); - } else { - // TODO(bill): Handle invalid map case? - } - } - - for_array(i, files) { - GoToDefFileMap *f = &files[i]; - gb_sort_array(f->idents.data, f->idents.count, quick_ident_compare); - // gb_printf_err("%lld %.*s -> %lld\n", f->f->id, LIT(f->f->fullpath), f->idents.count); - } - - - - isize data_min_size = 0; - - u32 header_offset = cast(u32)data_min_size; gb_unused(header_offset); - data_min_size += gb_size_of(GoToDefHeader); - data_min_size = align_formula_isize(data_min_size, 8); - - u32 file_offset = cast(u32)data_min_size; - data_min_size += gb_size_of(GoToDefFile) * files.count; - data_min_size = align_formula_isize(data_min_size, 8); - - u32 file_path_offset = cast(u32)data_min_size; - data_min_size += file_path_memory_needed; - data_min_size = align_formula_isize(data_min_size, 8); - - u32 idents_offset = cast(u32)data_min_size; - data_min_size += gb_size_of(GoToDefIdent) * c->info.identifier_uses.count; - - - auto data = array_make(a, 0, data_min_size); - defer (array_free(&data)); - - GoToDefHeader header = {}; - gb_memmove(header.magic, "ogtd", 4); - header.version = 1; - header.files.length = cast(u32)files.count; - header.files.offset = file_offset; - - array_add_elems(&data, cast(u8 *)&header, gb_size_of(header)); - - array_resize(&data, data_min_size); - - auto binary_files = binary_array_from_data(header.files, data.data); - - u32 file_path_offset_index = file_path_offset; - u32 idents_offset_index = idents_offset; - for_array(i, files) { - GoToDefFileMap *f_map = &files[i]; - AstFile *f = f_map->f; - binary_files[i].id = cast(u32)f->id; - - binary_files[i].path.offset = file_path_offset_index; - binary_files[i].path.length = cast(u32)f->fullpath.len; - - binary_files[i].idents.offset = idents_offset_index; - binary_files[i].idents.length = cast(u32)f_map->idents.count; - - auto path = binary_array_from_data(binary_files[i].path, data.data); - gb_memmove(path.data, f->fullpath.text, f->fullpath.len); - path.data[f->fullpath.len] = 0; - - - auto idents = binary_array_from_data(binary_files[i].idents, data.data); - for_array(j, f_map->idents) { - Ast *ast = f_map->idents[j]; - GB_ASSERT(ast->kind == Ast_Ident); - - Entity *e = ast->Ident.entity; - TokenPos def = e->token.pos; - AstFile *def_file = e->file; - - if (def_file == nullptr) { - auto *def_file_found = string_map_get(&c->info.files, get_file_path_string(e->token.pos.file_id)); - if (def_file_found == nullptr) { - continue; - } - def_file = *def_file_found; - } - - isize file_index = file_id_map_to_index[def_file->id]; - GB_ASSERT(file_index >= 0); - - idents[j].use_offset = cast(u64)ast->Ident.token.pos.offset; - idents[j].len = cast(u32)ast->Ident.token.string.len; - idents[j].def_file_id = cast(u32)def_file->id; - idents[j].def_offset = cast(u64)e->token.pos.offset; - - // gb_printf_err("%llu %llu %llu %llu\n", idents[j].len, idents[j].use_offset, idents[j].def_file_id, idents[j].def_offset); - } - - file_path_offset_index += cast(u32)(f->fullpath.len + 1); - idents_offset_index += cast(u32)(f_map->idents.count * gb_size_of(GoToDefIdent)); - } - - - gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.data, data.count*gb_size_of(*data.data)); -} - diff --git a/src/range_cache.cpp b/src/range_cache.cpp index 1f98c4b9e..fc85e2a2e 100644 --- a/src/range_cache.cpp +++ b/src/range_cache.cpp @@ -59,12 +59,12 @@ gb_internal bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) { } -gb_internal bool range_cache_index_exists(RangeCache *c, i64 index) { - for_array(i, c->ranges) { - RangeValue v = c->ranges[i]; - if (v.lo <= index && index <= v.hi) { - return true; - } - } - return false; -} +// gb_internal bool range_cache_index_exists(RangeCache *c, i64 index) { +// for_array(i, c->ranges) { +// RangeValue v = c->ranges[i]; +// if (v.lo <= index && index <= v.hi) { +// return true; +// } +// } +// return false; +// } diff --git a/src/string.cpp b/src/string.cpp index aeb31c7b0..8cce0f1ef 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -89,14 +89,6 @@ gb_internal char *alloc_cstring(gbAllocator a, String s) { return c_str; } -gb_internal char *cstring_duplicate(gbAllocator a, char const *s) { - isize len = gb_strlen(s); - char *c_str = gb_alloc_array(a, char, len+1); - gb_memmove(c_str, s, len); - c_str[len] = '\0'; - return c_str; -} - gb_internal gb_inline bool str_eq_ignore_case(String const &a, String const &b) { @@ -166,12 +158,6 @@ gb_internal isize string_index_byte(String const &s, u8 x) { return -1; } -gb_internal GB_COMPARE_PROC(string_cmp_proc) { - String x = *(String *)a; - String y = *(String *)b; - return string_compare(x, y); -} - gb_internal gb_inline bool str_eq(String const &a, String const &b) { if (a.len != b.len) return false; return memcmp(a.text, b.text, a.len) == 0; diff --git a/src/string_map.cpp b/src/string_map.cpp index e289d4c9b..9f9374ece 100644 --- a/src/string_map.cpp +++ b/src/string_map.cpp @@ -18,8 +18,6 @@ gb_internal gb_inline bool string_hash_key_equal(StringHashKey const &a, StringH } return false; } -gb_internal bool operator==(StringHashKey const &a, StringHashKey const &b) { return string_hash_key_equal(a, b); } -gb_internal bool operator!=(StringHashKey const &a, StringHashKey const &b) { return !string_hash_key_equal(a, b); } template struct StringMapEntry { diff --git a/src/threading.cpp b/src/threading.cpp index 511d1b477..b74d087b4 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -1,6 +1,10 @@ #if defined(GB_SYSTEM_LINUX) #include #endif +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4505) +#endif struct BlockingMutex; struct RecursiveMutex; @@ -269,48 +273,6 @@ struct MutexGuard { } #endif - - -struct Barrier { - BlockingMutex mutex; - Condition cond; - isize index; - isize generation_id; - isize thread_count; -}; - -gb_internal void barrier_init(Barrier *b, isize thread_count) { - mutex_init(&b->mutex); - condition_init(&b->cond); - b->index = 0; - b->generation_id = 0; - b->thread_count = 0; -} - -gb_internal void barrier_destroy(Barrier *b) { - condition_destroy(&b->cond); - mutex_destroy(&b->mutex); -} - -// Returns true if it is the leader -gb_internal bool barrier_wait(Barrier *b) { - mutex_lock(&b->mutex); - defer (mutex_unlock(&b->mutex)); - isize local_gen = b->generation_id; - b->index += 1; - if (b->index < b->thread_count) { - while (local_gen == b->generation_id && b->index < b->thread_count) { - condition_wait(&b->cond, &b->mutex); - } - return false; - } - b->index = 0; - b->generation_id += 1; - condition_broadcast(&b->cond); - return true; -} - - gb_internal u32 thread_current_id(void) { @@ -494,3 +456,7 @@ gb_internal void thread_set_name(Thread *t, char const *name) { #endif } + +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index c8e24f01d..b1d3883c6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -430,15 +430,6 @@ gb_internal Selection sub_selection(Selection const &sel, isize offset) { return res; } -gb_internal Selection sub_selection_with_length(Selection const &sel, isize offset, isize len) { - Selection res = {}; - res.index.data = sel.index.data + offset; - res.index.count = gb_max(len, gb_max(sel.index.count - offset, 0)); - res.index.capacity = res.index.count; - return res; -} - - gb_global Type basic_types[] = { {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, @@ -1089,15 +1080,6 @@ gb_internal Type *alloc_type_proc(Scope *scope, Type *params, isize param_count, gb_internal bool is_type_valid_for_keys(Type *t); -gb_internal Type *alloc_type_map(i64 count, Type *key, Type *value) { - if (key != nullptr) { - GB_ASSERT(value != nullptr); - } - Type *t = alloc_type(Type_Map); - t->Map.key = key; - t->Map.value = value; - return t; -} gb_internal Type *alloc_type_bit_set() { Type *t = alloc_type(Type_BitSet); @@ -1152,19 +1134,6 @@ gb_internal bool is_type_named(Type *t) { } return t->kind == Type_Named; } -gb_internal bool is_type_named_alias(Type *t) { - if (!is_type_named(t)) { - return false; - } - Entity *e = t->Named.type_name; - if (e == nullptr) { - return false; - } - if (e->kind != Entity_TypeName) { - return false; - } - return e->TypeName.is_type_alias; -} gb_internal bool is_type_boolean(Type *t) { // t = core_type(t); @@ -1329,27 +1298,6 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) { } return false; } -gb_internal bool is_type_f16(Type *t) { - t = core_type(t); - if (t->kind == Type_Basic) { - return t->Basic.kind == Basic_f16; - } - return false; -} -gb_internal bool is_type_f32(Type *t) { - t = core_type(t); - if (t->kind == Type_Basic) { - return t->Basic.kind == Basic_f32; - } - return false; -} -gb_internal bool is_type_f64(Type *t) { - t = core_type(t); - if (t->kind == Type_Basic) { - return t->Basic.kind == Basic_f64; - } - return false; -} gb_internal bool is_type_pointer(Type *t) { t = base_type(t); if (t->kind == Type_Basic) { @@ -1550,10 +1498,6 @@ gb_internal bool is_type_asm_proc(Type *t) { t = base_type(t); return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm; } -gb_internal bool is_type_poly_proc(Type *t) { - t = base_type(t); - return t->kind == Type_Proc && t->Proc.is_polymorphic; -} gb_internal bool is_type_simd_vector(Type *t) { t = base_type(t); return t->kind == Type_SimdVector; @@ -1915,11 +1859,6 @@ gb_internal bool is_type_empty_union(Type *t) { t = base_type(t); return t->kind == Type_Union && t->Union.variants.count == 0; } -gb_internal bool is_type_empty_struct(Type *t) { - t = base_type(t); - return t->kind == Type_Struct && !t->Struct.is_raw_union && t->Struct.fields.count == 0; -} - gb_internal bool is_type_valid_for_keys(Type *t) { t = core_type(t); @@ -4051,20 +3990,6 @@ gb_internal Type *reduce_tuple_to_single_type(Type *original_type) { return original_type; } - -gb_internal Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { - Type *t = alloc_type_struct(); - t->Struct.fields = slice_make(heap_allocator(), field_count); - - Scope *scope = nullptr; - for_array(i, t->Struct.fields) { - t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); - } - t->Struct.is_packed = is_packed; - - return t; -} - gb_internal Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { if (field_count == 0) { return nullptr; -- cgit v1.2.3 From e98f1a28e68e82753728f58b3465793192b74f9d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Dec 2022 11:53:13 +0000 Subject: Change `tav` to be a pointer internally --- src/check_expr.cpp | 68 ++++++++++++++++++++++---------------------- src/check_stmt.cpp | 10 +++---- src/check_type.cpp | 4 +-- src/checker.cpp | 22 +++++++------- src/llvm_backend_const.cpp | 56 ++++++++++++++++++------------------ src/llvm_backend_expr.cpp | 32 ++++++++++----------- src/llvm_backend_proc.cpp | 20 ++++++------- src/llvm_backend_stmt.cpp | 34 +++++++++++----------- src/llvm_backend_utility.cpp | 12 ++++---- src/parser.cpp | 8 ++++-- src/parser.hpp | 7 +++-- 11 files changed, 140 insertions(+), 133 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ed1ddd1f1..654dec051 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2119,7 +2119,7 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { return true; } ast_node(ta, TypeAssertion, expr); - TypeAndValue tv = ta->expr->tav; + TypeAndValue tv = ta->expr->tav(); if (is_type_pointer(tv.type)) { return false; } @@ -2590,7 +2590,7 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod TokenPos pos = ast_token(x->expr).pos; if (x_is_untyped) { if (x->expr != nullptr) { - x->expr->tav.is_lhs = true; + x->expr->tav().is_lhs = true; } x->mode = Addressing_Value; if (type_hint) { @@ -3567,9 +3567,9 @@ gb_internal Operand make_operand_from_node(Ast *node) { GB_ASSERT(node != nullptr); Operand x = {}; x.expr = node; - x.mode = node->tav.mode; - x.type = node->tav.type; - x.value = node->tav.value; + x.mode = node->tav().mode; + x.type = node->tav().type; + x.value = node->tav().value; return x; } @@ -3579,8 +3579,8 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, ExprInfo *old = check_get_expr_info(c, e); if (old == nullptr) { if (type != nullptr && type != t_invalid) { - if (e->tav.type == nullptr || e->tav.type == t_invalid) { - add_type_and_value(c->info, e, e->tav.mode, type ? type : e->tav.type, e->tav.value); + if (e->tav().type == nullptr || e->tav().type == t_invalid) { + add_type_and_value(c->info, e, e->tav().mode, type ? type : e->tav().type, e->tav().value); if (e->kind == Ast_TernaryIfExpr) { update_untyped_expr_type(c, e->TernaryIfExpr.x, type, final); update_untyped_expr_type(c, e->TernaryIfExpr.y, type, final); @@ -4146,7 +4146,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } if (cl->elems[0]->kind == Ast_FieldValue) { - if (is_type_struct(node->tav.type)) { + if (is_type_struct(node->tav().type)) { bool found = false; for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -4155,10 +4155,10 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; - Selection sub_sel = lookup_field(node->tav.type, name, false); + Selection sub_sel = lookup_field(node->tav().type, name, false); defer (array_free(&sub_sel.index)); if (sub_sel.index[0] == index) { - value = fv->value->tav.value; + value = fv->value->tav().value; found = true; break; } @@ -4167,7 +4167,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v // Use the zero value if it is not found value = {}; } - } else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) { + } else if (is_type_array(node->tav().type) || is_type_enumerated_array(node->tav().type)) { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; if (elem->kind != Ast_FieldValue) { @@ -4176,8 +4176,8 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -4187,39 +4187,39 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v i64 corrected_index = index; - if (is_type_enumerated_array(node->tav.type)) { - Type *bt = base_type(node->tav.type); + if (is_type_enumerated_array(node->tav().type)) { + Type *bt = base_type(node->tav().type); GB_ASSERT(bt->kind == Type_EnumeratedArray); corrected_index = index + exact_value_to_i64(*bt->EnumeratedArray.min_value); } if (op != Token_RangeHalf) { if (lo <= corrected_index && corrected_index <= hi) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; } } else { if (lo <= corrected_index && corrected_index < hi) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; } } } else { - TypeAndValue index_tav = fv->field->tav; + TypeAndValue index_tav = fv->field->tav(); GB_ASSERT(index_tav.mode == Addressing_Constant); ExactValue index_value = index_tav.value; - if (is_type_enumerated_array(node->tav.type)) { - Type *bt = base_type(node->tav.type); + if (is_type_enumerated_array(node->tav().type)) { + Type *bt = base_type(node->tav().type); GB_ASSERT(bt->kind == Type_EnumeratedArray); index_value = exact_value_sub(index_value, *bt->EnumeratedArray.min_value); } i64 field_index = exact_value_to_i64(index_value); if (index == field_index) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value;; @@ -4241,7 +4241,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v return value; } - TypeAndValue tav = cl->elems[index]->tav; + TypeAndValue tav = cl->elems[index]->tav(); if (tav.mode == Addressing_Constant) { if (success_) *success_ = true; if (finish_) *finish_ = false; @@ -8663,7 +8663,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Ast *e = cl->elems[i]; GB_ASSERT(e->kind != Ast_FieldValue); - TypeAndValue tav = e->tav; + TypeAndValue tav = e->tav(); if (tav.mode != Addressing_Constant) { continue; } @@ -8863,9 +8863,9 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast if (se->modified_call) { // Prevent double evaluation o->expr = node; - o->type = node->tav.type; - o->value = node->tav.value; - o->mode = node->tav.mode; + o->type = node->tav().type; + o->value = node->tav().value; + o->mode = node->tav().mode; return Expr_Expr; } @@ -8927,9 +8927,9 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast } Operand y = {}; - y.mode = first_arg->tav.mode; - y.type = first_arg->tav.type; - y.value = first_arg->tav.value; + y.mode = first_arg->tav().mode; + y.type = first_arg->tav().type; + y.value = first_arg->tav().value; if (check_is_assignable_to(c, &y, first_type)) { // Do nothing, it's valid @@ -9385,7 +9385,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(bl, BasicLit, node); Type *t = t_invalid; - switch (node->tav.value.kind) { + switch (node->tav().value.kind) { case ExactValue_String: t = t_untyped_string; break; case ExactValue_Float: t = t_untyped_float; break; case ExactValue_Complex: t = t_untyped_complex; break; @@ -9403,7 +9403,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast o->mode = Addressing_Constant; o->type = t; - o->value = node->tav.value; + o->value = node->tav().value; case_end; case_ast_node(bd, BasicDirective, node); @@ -9859,12 +9859,12 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { } else { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (elem->tav.mode != Addressing_Constant) { - // if (elem->tav.value.kind != ExactValue_Invalid) { + if (elem->tav().mode != Addressing_Constant) { + // if (elem->tav().value.kind != ExactValue_Invalid) { return false; // } } - if (!is_exact_value_zero(elem->tav.value)) { + if (!is_exact_value_zero(elem->tav().value)) { return false; } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index cf111e84c..7ba23ac67 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -8,7 +8,7 @@ gb_internal bool is_diverging_expr(Ast *expr) { return name == "panic"; } Ast *proc = unparen_expr(expr->CallExpr.proc); - TypeAndValue tv = proc->tav; + TypeAndValue tv = proc->tav(); if (tv.mode == Addressing_Builtin) { Entity *e = entity_of_node(proc); BuiltinProcId id = BuiltinProc_Invalid; @@ -250,7 +250,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) { case_ast_node(ws, WhenStmt, node); // TODO(bill): Is this logic correct for when statements? - auto const &tv = ws->cond->tav; + auto const &tv = ws->cond->tav(); if (tv.mode != Addressing_Constant) { // NOTE(bill): Check the things regardless as a bug occurred earlier if (ws->else_stmt != nullptr) { @@ -411,7 +411,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Ast *ln = unparen_expr(lhs->expr); if (ln->kind == Ast_IndexExpr) { Ast *x = ln->IndexExpr.expr; - TypeAndValue tav = x->tav; + TypeAndValue tav = x->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); if (tav.mode != Addressing_Variable) { if (!is_type_pointer(tav.type)) { @@ -1497,7 +1497,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) break; } - switch (be->left->tav.mode) { + switch (be->left->tav().mode) { case Addressing_Context: case Addressing_Variable: case Addressing_MapIndex: @@ -2331,7 +2331,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(e->token, "A static variable declaration with a default value must be constant"); } else { Ast *value = vd->values[i]; - if (value->tav.mode != Addressing_Constant) { + if (value->tav().mode != Addressing_Constant) { error(e->token, "A static variable declaration with a default value must be constant"); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 4634e1fbe..3d4bab3e2 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2569,8 +2569,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_end; case_ast_node(tt, TypeidType, e); - e->tav.mode = Addressing_Type; - e->tav.type = t_typeid; + e->tav().mode = Addressing_Type; + e->tav().type = t_typeid; *type = t_typeid; set_base_type(named_type, *type); return true; diff --git a/src/checker.cpp b/src/checker.cpp index 14a0e5f4c..0f64c6ae9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1287,13 +1287,13 @@ gb_internal void destroy_checker(Checker *c) { gb_internal TypeAndValue type_and_value_of_expr(Ast *expr) { TypeAndValue tav = {}; if (expr != nullptr) { - tav = expr->tav; + tav = expr->tav(); } return tav; } gb_internal Type *type_of_expr(Ast *expr) { - TypeAndValue tav = expr->tav; + TypeAndValue tav = expr->tav(); if (tav.mode != Addressing_Invalid) { return tav.type; } @@ -1462,20 +1462,20 @@ gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mo Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; - expr->tav.mode = mode; - if (type != nullptr && expr->tav.type != nullptr && - is_type_any(type) && is_type_untyped(expr->tav.type)) { + expr->tav().mode = mode; + if (type != nullptr && expr->tav().type != nullptr && + is_type_any(type) && is_type_untyped(expr->tav().type)) { // ignore } else { - expr->tav.type = type; + expr->tav().type = type; } if (mode == Addressing_Constant || mode == Addressing_Invalid) { - expr->tav.value = value; + expr->tav().value = value; } else if (mode == Addressing_Value && is_type_typeid(type)) { - expr->tav.value = value; + expr->tav().value = value; } else if (mode == Addressing_Value && is_type_proc(type)) { - expr->tav.value = value; + expr->tav().value = value; } expr = unparen_expr(expr); @@ -3635,8 +3635,8 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (value != nullptr) { if (value->kind == Ast_BasicLit && value->BasicLit.token.kind == Token_String) { String v = {}; - if (value->tav.value.kind == ExactValue_String) { - v = value->tav.value.value_string; + if (value->tav().value.kind == ExactValue_String) { + v = value->tav().value.value_string; } if (v == "file") { kind = EntityVisiblity_PrivateToFile; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index ee564bbf1..6c5bb153f 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -57,7 +57,7 @@ gb_internal bool lb_is_const_nil(lbValue value) { gb_internal bool lb_is_expr_constant_zero(Ast *expr) { GB_ASSERT(expr != nullptr); - auto v = exact_value_to_integer(expr->tav.value); + auto v = exact_value_to_integer(expr->tav().value); if (v.kind == ExactValue_Integer) { return big_int_cmp_zero(&v.value_integer) == 0; } @@ -720,8 +720,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -732,7 +732,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -743,11 +743,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav; + TypeAndValue index_tav = fv->field->tav(); GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -769,7 +769,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; + TypeAndValue tav = cl->elems[i]->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -804,8 +804,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -816,7 +816,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -827,11 +827,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav; + TypeAndValue index_tav = fv->field->tav(); GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -853,7 +853,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count); for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; + TypeAndValue tav = cl->elems[i]->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -887,8 +887,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -899,7 +899,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -910,11 +910,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav; + TypeAndValue index_tav = fv->field->tav(); GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -932,7 +932,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; } else { for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav; + TypeAndValue tav = cl->elems[i]->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -974,7 +974,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, cl->elems[i]); String name = fv->field->Ident.token.string; - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); Selection sel = lookup_field(type, name, false); @@ -989,7 +989,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } else { for_array(i, cl->elems) { Entity *f = type->Struct.fields[i]; - TypeAndValue tav = cl->elems[i]->tav; + TypeAndValue tav = cl->elems[i]->tav(); ExactValue val = {}; if (tav.mode != Addressing_Invalid) { val = tav.value; @@ -1073,7 +1073,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Ast *e = cl->elems[i]; GB_ASSERT(e->kind != Ast_FieldValue); - TypeAndValue tav = e->tav; + TypeAndValue tav = e->tav(); if (tav.mode != Addressing_Constant) { continue; } @@ -1106,8 +1106,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -1122,7 +1122,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(lo <= hi); - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); @@ -1130,11 +1130,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo values[offset] = val; } } else { - TypeAndValue index_tav = fv->field->tav; + TypeAndValue index_tav = fv->field->tav(); GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); GB_ASSERT(index < max_count); - TypeAndValue tav = fv->value->tav; + TypeAndValue tav = fv->value->tav(); LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); @@ -1156,7 +1156,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)total_count); for_array(i, cl->elems) { - TypeAndValue tav = cl->elems[i]->tav; + TypeAndValue tav = cl->elems[i]->tav(); GB_ASSERT(tav.mode != Addressing_Invalid); i64 offset = matrix_row_major_index_to_offset(type, i); values[offset] = lb_const_value(m, elem_type, tav.value, allow_local).value; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d574caf4c..794ed7720 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1330,7 +1330,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { TypeAndValue tv = type_and_value_of_expr(expr); - if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) { + if (is_type_matrix(be->left->tav().type) || is_type_matrix(be->right->tav().type)) { lbValue left = lb_build_expr(p, be->left); lbValue right = lb_build_expr(p, be->right); return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false); @@ -1372,12 +1372,12 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { case Token_CmpEq: case Token_NotEq: - if (is_type_untyped_nil(be->right->tav.type)) { + if (is_type_untyped_nil(be->right->tav().type)) { lbValue left = lb_build_expr(p, be->left); lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, left); Type *type = default_type(tv.type); return lb_emit_conv(p, cmp, type); - } else if (is_type_untyped_nil(be->left->tav.type)) { + } else if (is_type_untyped_nil(be->left->tav().type)) { lbValue right = lb_build_expr(p, be->right); lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right); Type *type = default_type(tv.type); @@ -1392,11 +1392,11 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue left = {}; lbValue right = {}; - if (be->left->tav.mode == Addressing_Type) { - left = lb_typeid(p->module, be->left->tav.type); + if (be->left->tav().mode == Addressing_Type) { + left = lb_typeid(p->module, be->left->tav().type); } - if (be->right->tav.mode == Addressing_Type) { - right = lb_typeid(p->module, be->right->tav.type); + if (be->right->tav().mode == Addressing_Type) { + right = lb_typeid(p->module, be->right->tav().type); } if (left.value == nullptr) left = lb_build_expr(p, be->left); if (right.value == nullptr) right = lb_build_expr(p, be->right); @@ -3093,7 +3093,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): The commented out code below is just for debug purposes only // if (is_type_untyped(type)) { - // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); + // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav().type), expr); // GB_PANIC("%s\n", type_to_string(tv.type)); // } @@ -3514,8 +3514,8 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slicefield)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; + TypeAndValue lo_tav = ie->left->tav(); + TypeAndValue hi_tav = ie->right->tav(); GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -3556,7 +3556,7 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slicefield->tav; + auto tav = fv->field->tav(); GB_ASSERT(tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(tav.value); @@ -3632,7 +3632,7 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { return lb_addr_soa_variable(val, index, ie->index); } - if (ie->expr->tav.mode == Addressing_SoaVariable) { + if (ie->expr->tav().mode == Addressing_SoaVariable) { // SOA Structures for slices/dynamic arrays GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); @@ -4451,8 +4451,8 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { a = lb_addr_get_ptr(p, addr); } - GB_ASSERT(is_type_array(expr->tav.type)); - return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); + GB_ASSERT(is_type_array(expr->tav().type)); + return lb_addr_swizzle(a, expr->tav().type, swizzle_count, swizzle_indices); } Selection sel = lookup_field(type, selector, false); @@ -4621,7 +4621,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_ast_node(ce, CallExpr, expr); BuiltinProcId builtin_id = BuiltinProc_Invalid; - if (ce->proc->tav.mode == Addressing_Builtin) { + if (ce->proc->tav().mode == Addressing_Builtin) { Entity *e = entity_of_node(ce->proc); if (e != nullptr) { builtin_id = cast(BuiltinProcId)e->Builtin.id; @@ -4629,7 +4629,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { builtin_id = BuiltinProc_DIRECTIVE; } } - auto const &tv = expr->tav; + auto const &tv = expr->tav(); if (builtin_id == BuiltinProc_swizzle && is_type_array(tv.type)) { // NOTE(bill, 2021-08-09): `swizzle` has some bizarre semantics so it needs to be diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 384d29ca7..546d49027 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1516,7 +1516,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn BigInt bi_count = {}; big_int_from_i64(&bi_count, count); - TypeAndValue const &tv = ce->args[1]->tav; + TypeAndValue const &tv = ce->args[1]->tav(); ExactValue val = exact_value_to_integer(tv.value); GB_ASSERT(val.kind == ExactValue_Integer); BigInt *bi = &val.value_integer; @@ -2428,16 +2428,16 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_type_equal_proc: - return lb_equal_proc_for_type(p->module, ce->args[0]->tav.type); + return lb_equal_proc_for_type(p->module, ce->args[0]->tav().type); case BuiltinProc_type_hasher_proc: - return lb_hasher_proc_for_type(p->module, ce->args[0]->tav.type); + return lb_hasher_proc_for_type(p->module, ce->args[0]->tav().type); case BuiltinProc_type_map_info: - return lb_gen_map_info_ptr(p->module, ce->args[0]->tav.type); + return lb_gen_map_info_ptr(p->module, ce->args[0]->tav().type); case BuiltinProc_type_map_cell_info: - return lb_gen_map_cell_info_ptr(p->module, ce->args[0]->tav.type); + return lb_gen_map_cell_info_ptr(p->module, ce->args[0]->tav().type); case BuiltinProc_fixed_point_mul: @@ -2505,7 +2505,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_prefetch_write_data: { lbValue ptr = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_rawptr); - unsigned long long locality = cast(unsigned long long)exact_value_to_i64(ce->args[1]->tav.value); + unsigned long long locality = cast(unsigned long long)exact_value_to_i64(ce->args[1]->tav().value); unsigned long long rw = 0; unsigned long long cache = 0; switch (id) { @@ -3060,8 +3060,8 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - if (proc_expr->tav.mode == Addressing_Constant) { - ExactValue v = proc_expr->tav.value; + if (proc_expr->tav().mode == Addressing_Constant) { + ExactValue v = proc_expr->tav().value; switch (v.kind) { case ExactValue_Integer: { @@ -3070,7 +3070,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); x.type = t_uintptr; x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav.type); + value = lb_emit_conv(p, x, proc_expr->tav().type); break; } case ExactValue_Pointer: @@ -3080,7 +3080,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); x.type = t_uintptr; x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav.type); + value = lb_emit_conv(p, x, proc_expr->tav().type); break; } } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 6400a8a9d..e0e991b4d 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -952,11 +952,11 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * TokenKind op = expr->BinaryExpr.op.kind; Ast *start_expr = expr->BinaryExpr.left; Ast *end_expr = expr->BinaryExpr.right; - GB_ASSERT(start_expr->tav.mode == Addressing_Constant); - GB_ASSERT(end_expr->tav.mode == Addressing_Constant); + GB_ASSERT(start_expr->tav().mode == Addressing_Constant); + GB_ASSERT(end_expr->tav().mode == Addressing_Constant); - ExactValue start = start_expr->tav.value; - ExactValue end = end_expr->tav.value; + ExactValue start = start_expr->tav().value; + ExactValue end = end_expr->tav().value; if (op != Token_RangeHalf) { // .. [start, end] (or ..=) ExactValue index = exact_value_i64(0); for (ExactValue val = start; @@ -1006,16 +1006,16 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * if (val0_type) val0_addr = lb_build_addr(p, rs->val0); if (val1_type) val1_addr = lb_build_addr(p, rs->val1); - GB_ASSERT(expr->tav.mode == Addressing_Constant); + GB_ASSERT(expr->tav().mode == Addressing_Constant); - Type *t = base_type(expr->tav.type); + Type *t = base_type(expr->tav().type); switch (t->kind) { case Type_Basic: GB_ASSERT(is_type_string(t)); { - ExactValue value = expr->tav.value; + ExactValue value = expr->tav().value; GB_ASSERT(value.kind == ExactValue_String); String str = value.value_string; Rune codepoint = 0; @@ -1109,7 +1109,7 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo if (is_ast_range(expr)) { return false; } - if (expr->tav.mode == Addressing_Type) { + if (expr->tav().mode == Addressing_Type) { GB_ASSERT(is_typeid); continue; } @@ -1209,12 +1209,12 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (switch_instr != nullptr) { lbValue on_val = {}; - if (expr->tav.mode == Addressing_Type) { + if (expr->tav().mode == Addressing_Type) { GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav.type); + lbValue e = lb_typeid(p->module, expr->tav().type); on_val = lb_emit_conv(p, e, tag.type); } else { - GB_ASSERT(expr->tav.mode == Addressing_Constant); + GB_ASSERT(expr->tav().mode == Addressing_Constant); GB_ASSERT(!is_ast_range(expr)); on_val = lb_build_expr(p, expr); @@ -1245,9 +1245,9 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs); cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); } else { - if (expr->tav.mode == Addressing_Type) { + if (expr->tav().mode == Addressing_Type) { GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav.type); + lbValue e = lb_typeid(p->module, expr->tav().type); e = lb_emit_conv(p, e, tag.type); cond = lb_emit_comp(p, Token_CmpEq, tag, e); } else { @@ -1476,11 +1476,11 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { if (vd->values.count > 0) { GB_ASSERT(vd->names.count == vd->values.count); Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav.mode == Addressing_Constant || - ast_value->tav.mode == Addressing_Invalid); + GB_ASSERT(ast_value->tav().mode == Addressing_Constant || + ast_value->tav().mode == Addressing_Invalid); bool allow_local = false; - value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local); + value = lb_const_value(p->module, ast_value->tav().type, ast_value->tav().value, allow_local); } Ast *ident = vd->names[i]; @@ -2068,7 +2068,7 @@ gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) { op_ += Token_Add - Token_AddEq; // Convert += to + TokenKind op = cast(TokenKind)op_; if (op == Token_CmpAnd || op == Token_CmpOr) { - Type *type = as->lhs[0]->tav.type; + Type *type = as->lhs[0]->tav().type; lbValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); lbAddr lhs = lb_build_addr(p, as->lhs[0]); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index dbed32b82..6abcdfc04 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1929,7 +1929,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, Stri gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); - auto tav = ce->args[0]->tav; + auto tav = ce->args[0]->tav(); GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name)); @@ -1939,7 +1939,7 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) ast_node(ce, CallExpr, expr); lbModule *m = p->module; - auto tav = ce->args[0]->tav; + auto tav = ce->args[0]->tav(); GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; lbAddr dst = lb_handle_objc_find_or_register_selector(p, name); @@ -1975,7 +1975,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); - auto tav = ce->args[0]->tav; + auto tav = ce->args[0]->tav(); GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); @@ -1985,7 +1985,7 @@ gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); lbModule *m = p->module; - auto tav = ce->args[0]->tav; + auto tav = ce->args[0]->tav(); GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; lbAddr dst = lb_handle_objc_find_or_register_class(p, name); @@ -2045,8 +2045,8 @@ gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { lbValue id = lb_handle_objc_id(p, ce->args[1]); Ast *sel_expr = ce->args[2]; - GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); - lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav.value.value_string)); + GB_ASSERT(sel_expr->tav().value.kind == ExactValue_String); + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav().value.value_string)); array_add(&args, id); array_add(&args, sel); diff --git a/src/parser.cpp b/src/parser.cpp index 436498c51..42d8f62cf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -71,6 +71,7 @@ gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind) { Ast *node = cast(Ast *)gb_alloc(a, size); node->kind = kind; node->file_id = f ? f->id : 0; + node->tav_ = gb_alloc_item(a, TypeAndValue); global_total_node_memory_allocated.fetch_add(size); @@ -106,6 +107,9 @@ gb_internal Ast *clone_ast(Ast *node) { AstFile *f = node->thread_safe_file(); Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); + TypeAndValue *new_tav = gb_alloc_item(ast_allocator(f), TypeAndValue); + *new_tav = *node->tav_; + n->tav_ = new_tav; switch (n->kind) { default: GB_PANIC("Unhandled Ast %.*s", LIT(ast_strings[n->kind])); break; @@ -650,8 +654,8 @@ gb_internal String string_value_from_token(AstFile *f, Token const &token) { gb_internal Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *result = alloc_ast_node(f, Ast_BasicLit); result->BasicLit.token = basic_lit; - result->tav.mode = Addressing_Constant; - result->tav.value = exact_value_from_token(f, basic_lit); + result->tav().mode = Addressing_Constant; + result->tav().value = exact_value_from_token(f, basic_lit); return result; } diff --git a/src/parser.hpp b/src/parser.hpp index 7d292ffce..e3d6b42d8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -754,7 +754,7 @@ struct AstCommonStuff { u8 state_flags; u8 viral_state_flags; i32 file_id; - TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size + TypeAndValue *tav_; // TODO(bill): Make this a pointer to minimize 'Ast' size }; struct Ast { @@ -762,7 +762,7 @@ struct Ast { u8 state_flags; u8 viral_state_flags; i32 file_id; - TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size + TypeAndValue *tav_; // TODO(bill): Make this a pointer to minimize 'Ast' size // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { @@ -771,6 +771,9 @@ struct Ast { #undef AST_KIND }; + gb_inline TypeAndValue &tav() const { + return *this->tav_; + } // NOTE(bill): I know I dislike methods but this is hopefully a temporary thing // for refactoring purposes -- cgit v1.2.3 From 9b278db9934913367a8e186b9c6aa9c03017f3d4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Dec 2022 12:01:41 +0000 Subject: Revert "Change `tav` to be a pointer internally" This reverts commit e98f1a28e68e82753728f58b3465793192b74f9d. --- src/check_expr.cpp | 68 ++++++++++++++++++++++---------------------- src/check_stmt.cpp | 10 +++---- src/check_type.cpp | 4 +-- src/checker.cpp | 22 +++++++------- src/llvm_backend_const.cpp | 56 ++++++++++++++++++------------------ src/llvm_backend_expr.cpp | 32 ++++++++++----------- src/llvm_backend_proc.cpp | 20 ++++++------- src/llvm_backend_stmt.cpp | 34 +++++++++++----------- src/llvm_backend_utility.cpp | 12 ++++---- src/parser.cpp | 8 ++---- src/parser.hpp | 7 ++--- 11 files changed, 133 insertions(+), 140 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 654dec051..ed1ddd1f1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2119,7 +2119,7 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { return true; } ast_node(ta, TypeAssertion, expr); - TypeAndValue tv = ta->expr->tav(); + TypeAndValue tv = ta->expr->tav; if (is_type_pointer(tv.type)) { return false; } @@ -2590,7 +2590,7 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod TokenPos pos = ast_token(x->expr).pos; if (x_is_untyped) { if (x->expr != nullptr) { - x->expr->tav().is_lhs = true; + x->expr->tav.is_lhs = true; } x->mode = Addressing_Value; if (type_hint) { @@ -3567,9 +3567,9 @@ gb_internal Operand make_operand_from_node(Ast *node) { GB_ASSERT(node != nullptr); Operand x = {}; x.expr = node; - x.mode = node->tav().mode; - x.type = node->tav().type; - x.value = node->tav().value; + x.mode = node->tav.mode; + x.type = node->tav.type; + x.value = node->tav.value; return x; } @@ -3579,8 +3579,8 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, ExprInfo *old = check_get_expr_info(c, e); if (old == nullptr) { if (type != nullptr && type != t_invalid) { - if (e->tav().type == nullptr || e->tav().type == t_invalid) { - add_type_and_value(c->info, e, e->tav().mode, type ? type : e->tav().type, e->tav().value); + if (e->tav.type == nullptr || e->tav.type == t_invalid) { + add_type_and_value(c->info, e, e->tav.mode, type ? type : e->tav.type, e->tav.value); if (e->kind == Ast_TernaryIfExpr) { update_untyped_expr_type(c, e->TernaryIfExpr.x, type, final); update_untyped_expr_type(c, e->TernaryIfExpr.y, type, final); @@ -4146,7 +4146,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } if (cl->elems[0]->kind == Ast_FieldValue) { - if (is_type_struct(node->tav().type)) { + if (is_type_struct(node->tav.type)) { bool found = false; for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -4155,10 +4155,10 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; - Selection sub_sel = lookup_field(node->tav().type, name, false); + Selection sub_sel = lookup_field(node->tav.type, name, false); defer (array_free(&sub_sel.index)); if (sub_sel.index[0] == index) { - value = fv->value->tav().value; + value = fv->value->tav.value; found = true; break; } @@ -4167,7 +4167,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v // Use the zero value if it is not found value = {}; } - } else if (is_type_array(node->tav().type) || is_type_enumerated_array(node->tav().type)) { + } else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; if (elem->kind != Ast_FieldValue) { @@ -4176,8 +4176,8 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -4187,39 +4187,39 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v i64 corrected_index = index; - if (is_type_enumerated_array(node->tav().type)) { - Type *bt = base_type(node->tav().type); + if (is_type_enumerated_array(node->tav.type)) { + Type *bt = base_type(node->tav.type); GB_ASSERT(bt->kind == Type_EnumeratedArray); corrected_index = index + exact_value_to_i64(*bt->EnumeratedArray.min_value); } if (op != Token_RangeHalf) { if (lo <= corrected_index && corrected_index <= hi) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; } } else { if (lo <= corrected_index && corrected_index < hi) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; } } } else { - TypeAndValue index_tav = fv->field->tav(); + TypeAndValue index_tav = fv->field->tav; GB_ASSERT(index_tav.mode == Addressing_Constant); ExactValue index_value = index_tav.value; - if (is_type_enumerated_array(node->tav().type)) { - Type *bt = base_type(node->tav().type); + if (is_type_enumerated_array(node->tav.type)) { + Type *bt = base_type(node->tav.type); GB_ASSERT(bt->kind == Type_EnumeratedArray); index_value = exact_value_sub(index_value, *bt->EnumeratedArray.min_value); } i64 field_index = exact_value_to_i64(index_value); if (index == field_index) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value;; @@ -4241,7 +4241,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v return value; } - TypeAndValue tav = cl->elems[index]->tav(); + TypeAndValue tav = cl->elems[index]->tav; if (tav.mode == Addressing_Constant) { if (success_) *success_ = true; if (finish_) *finish_ = false; @@ -8663,7 +8663,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Ast *e = cl->elems[i]; GB_ASSERT(e->kind != Ast_FieldValue); - TypeAndValue tav = e->tav(); + TypeAndValue tav = e->tav; if (tav.mode != Addressing_Constant) { continue; } @@ -8863,9 +8863,9 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast if (se->modified_call) { // Prevent double evaluation o->expr = node; - o->type = node->tav().type; - o->value = node->tav().value; - o->mode = node->tav().mode; + o->type = node->tav.type; + o->value = node->tav.value; + o->mode = node->tav.mode; return Expr_Expr; } @@ -8927,9 +8927,9 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast } Operand y = {}; - y.mode = first_arg->tav().mode; - y.type = first_arg->tav().type; - y.value = first_arg->tav().value; + y.mode = first_arg->tav.mode; + y.type = first_arg->tav.type; + y.value = first_arg->tav.value; if (check_is_assignable_to(c, &y, first_type)) { // Do nothing, it's valid @@ -9385,7 +9385,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(bl, BasicLit, node); Type *t = t_invalid; - switch (node->tav().value.kind) { + switch (node->tav.value.kind) { case ExactValue_String: t = t_untyped_string; break; case ExactValue_Float: t = t_untyped_float; break; case ExactValue_Complex: t = t_untyped_complex; break; @@ -9403,7 +9403,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast o->mode = Addressing_Constant; o->type = t; - o->value = node->tav().value; + o->value = node->tav.value; case_end; case_ast_node(bd, BasicDirective, node); @@ -9859,12 +9859,12 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { } else { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (elem->tav().mode != Addressing_Constant) { - // if (elem->tav().value.kind != ExactValue_Invalid) { + if (elem->tav.mode != Addressing_Constant) { + // if (elem->tav.value.kind != ExactValue_Invalid) { return false; // } } - if (!is_exact_value_zero(elem->tav().value)) { + if (!is_exact_value_zero(elem->tav.value)) { return false; } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 7ba23ac67..cf111e84c 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -8,7 +8,7 @@ gb_internal bool is_diverging_expr(Ast *expr) { return name == "panic"; } Ast *proc = unparen_expr(expr->CallExpr.proc); - TypeAndValue tv = proc->tav(); + TypeAndValue tv = proc->tav; if (tv.mode == Addressing_Builtin) { Entity *e = entity_of_node(proc); BuiltinProcId id = BuiltinProc_Invalid; @@ -250,7 +250,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) { case_ast_node(ws, WhenStmt, node); // TODO(bill): Is this logic correct for when statements? - auto const &tv = ws->cond->tav(); + auto const &tv = ws->cond->tav; if (tv.mode != Addressing_Constant) { // NOTE(bill): Check the things regardless as a bug occurred earlier if (ws->else_stmt != nullptr) { @@ -411,7 +411,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Ast *ln = unparen_expr(lhs->expr); if (ln->kind == Ast_IndexExpr) { Ast *x = ln->IndexExpr.expr; - TypeAndValue tav = x->tav(); + TypeAndValue tav = x->tav; GB_ASSERT(tav.mode != Addressing_Invalid); if (tav.mode != Addressing_Variable) { if (!is_type_pointer(tav.type)) { @@ -1497,7 +1497,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) break; } - switch (be->left->tav().mode) { + switch (be->left->tav.mode) { case Addressing_Context: case Addressing_Variable: case Addressing_MapIndex: @@ -2331,7 +2331,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(e->token, "A static variable declaration with a default value must be constant"); } else { Ast *value = vd->values[i]; - if (value->tav().mode != Addressing_Constant) { + if (value->tav.mode != Addressing_Constant) { error(e->token, "A static variable declaration with a default value must be constant"); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 3d4bab3e2..4634e1fbe 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2569,8 +2569,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_end; case_ast_node(tt, TypeidType, e); - e->tav().mode = Addressing_Type; - e->tav().type = t_typeid; + e->tav.mode = Addressing_Type; + e->tav.type = t_typeid; *type = t_typeid; set_base_type(named_type, *type); return true; diff --git a/src/checker.cpp b/src/checker.cpp index 0f64c6ae9..14a0e5f4c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1287,13 +1287,13 @@ gb_internal void destroy_checker(Checker *c) { gb_internal TypeAndValue type_and_value_of_expr(Ast *expr) { TypeAndValue tav = {}; if (expr != nullptr) { - tav = expr->tav(); + tav = expr->tav; } return tav; } gb_internal Type *type_of_expr(Ast *expr) { - TypeAndValue tav = expr->tav(); + TypeAndValue tav = expr->tav; if (tav.mode != Addressing_Invalid) { return tav.type; } @@ -1462,20 +1462,20 @@ gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mo Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; - expr->tav().mode = mode; - if (type != nullptr && expr->tav().type != nullptr && - is_type_any(type) && is_type_untyped(expr->tav().type)) { + expr->tav.mode = mode; + if (type != nullptr && expr->tav.type != nullptr && + is_type_any(type) && is_type_untyped(expr->tav.type)) { // ignore } else { - expr->tav().type = type; + expr->tav.type = type; } if (mode == Addressing_Constant || mode == Addressing_Invalid) { - expr->tav().value = value; + expr->tav.value = value; } else if (mode == Addressing_Value && is_type_typeid(type)) { - expr->tav().value = value; + expr->tav.value = value; } else if (mode == Addressing_Value && is_type_proc(type)) { - expr->tav().value = value; + expr->tav.value = value; } expr = unparen_expr(expr); @@ -3635,8 +3635,8 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (value != nullptr) { if (value->kind == Ast_BasicLit && value->BasicLit.token.kind == Token_String) { String v = {}; - if (value->tav().value.kind == ExactValue_String) { - v = value->tav().value.value_string; + if (value->tav.value.kind == ExactValue_String) { + v = value->tav.value.value_string; } if (v == "file") { kind = EntityVisiblity_PrivateToFile; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 6c5bb153f..ee564bbf1 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -57,7 +57,7 @@ gb_internal bool lb_is_const_nil(lbValue value) { gb_internal bool lb_is_expr_constant_zero(Ast *expr) { GB_ASSERT(expr != nullptr); - auto v = exact_value_to_integer(expr->tav().value); + auto v = exact_value_to_integer(expr->tav.value); if (v.kind == ExactValue_Integer) { return big_int_cmp_zero(&v.value_integer) == 0; } @@ -720,8 +720,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -732,7 +732,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -743,11 +743,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav(); + TypeAndValue index_tav = fv->field->tav; GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -769,7 +769,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav(); + TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -804,8 +804,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -816,7 +816,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -827,11 +827,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav(); + TypeAndValue index_tav = fv->field->tav; GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -853,7 +853,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->EnumeratedArray.count); for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav(); + TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -887,8 +887,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -899,7 +899,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo hi += 1; } if (lo == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; @@ -910,11 +910,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo break; } } else { - TypeAndValue index_tav = fv->field->tav(); + TypeAndValue index_tav = fv->field->tav; GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); if (index == i) { - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; values[value_index++] = val; found = true; @@ -932,7 +932,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; } else { for (isize i = 0; i < elem_count; i++) { - TypeAndValue tav = cl->elems[i]->tav(); + TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); values[i] = lb_const_value(m, elem_type, tav.value, allow_local).value; } @@ -974,7 +974,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, cl->elems[i]); String name = fv->field->Ident.token.string; - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; GB_ASSERT(tav.mode != Addressing_Invalid); Selection sel = lookup_field(type, name, false); @@ -989,7 +989,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } else { for_array(i, cl->elems) { Entity *f = type->Struct.fields[i]; - TypeAndValue tav = cl->elems[i]->tav(); + TypeAndValue tav = cl->elems[i]->tav; ExactValue val = {}; if (tav.mode != Addressing_Invalid) { val = tav.value; @@ -1073,7 +1073,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Ast *e = cl->elems[i]; GB_ASSERT(e->kind != Ast_FieldValue); - TypeAndValue tav = e->tav(); + TypeAndValue tav = e->tav; if (tav.mode != Addressing_Constant) { continue; } @@ -1106,8 +1106,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo ast_node(fv, FieldValue, elem); if (is_ast_range(fv->field)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -1122,7 +1122,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(lo <= hi); - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); @@ -1130,11 +1130,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo values[offset] = val; } } else { - TypeAndValue index_tav = fv->field->tav(); + TypeAndValue index_tav = fv->field->tav; GB_ASSERT(index_tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(index_tav.value); GB_ASSERT(index < max_count); - TypeAndValue tav = fv->value->tav(); + TypeAndValue tav = fv->value->tav; LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); @@ -1156,7 +1156,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)total_count); for_array(i, cl->elems) { - TypeAndValue tav = cl->elems[i]->tav(); + TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); i64 offset = matrix_row_major_index_to_offset(type, i); values[offset] = lb_const_value(m, elem_type, tav.value, allow_local).value; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 794ed7720..d574caf4c 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1330,7 +1330,7 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { TypeAndValue tv = type_and_value_of_expr(expr); - if (is_type_matrix(be->left->tav().type) || is_type_matrix(be->right->tav().type)) { + if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) { lbValue left = lb_build_expr(p, be->left); lbValue right = lb_build_expr(p, be->right); return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false); @@ -1372,12 +1372,12 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { case Token_CmpEq: case Token_NotEq: - if (is_type_untyped_nil(be->right->tav().type)) { + if (is_type_untyped_nil(be->right->tav.type)) { lbValue left = lb_build_expr(p, be->left); lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, left); Type *type = default_type(tv.type); return lb_emit_conv(p, cmp, type); - } else if (is_type_untyped_nil(be->left->tav().type)) { + } else if (is_type_untyped_nil(be->left->tav.type)) { lbValue right = lb_build_expr(p, be->right); lbValue cmp = lb_emit_comp_against_nil(p, be->op.kind, right); Type *type = default_type(tv.type); @@ -1392,11 +1392,11 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue left = {}; lbValue right = {}; - if (be->left->tav().mode == Addressing_Type) { - left = lb_typeid(p->module, be->left->tav().type); + if (be->left->tav.mode == Addressing_Type) { + left = lb_typeid(p->module, be->left->tav.type); } - if (be->right->tav().mode == Addressing_Type) { - right = lb_typeid(p->module, be->right->tav().type); + if (be->right->tav.mode == Addressing_Type) { + right = lb_typeid(p->module, be->right->tav.type); } if (left.value == nullptr) left = lb_build_expr(p, be->left); if (right.value == nullptr) right = lb_build_expr(p, be->right); @@ -3093,7 +3093,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): The commented out code below is just for debug purposes only // if (is_type_untyped(type)) { - // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav().type), expr); + // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); // GB_PANIC("%s\n", type_to_string(tv.type)); // } @@ -3514,8 +3514,8 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slicefield)) { ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav(); - TypeAndValue hi_tav = ie->right->tav(); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; GB_ASSERT(lo_tav.mode == Addressing_Constant); GB_ASSERT(hi_tav.mode == Addressing_Constant); @@ -3556,7 +3556,7 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slicefield->tav(); + auto tav = fv->field->tav; GB_ASSERT(tav.mode == Addressing_Constant); i64 index = exact_value_to_i64(tav.value); @@ -3632,7 +3632,7 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { return lb_addr_soa_variable(val, index, ie->index); } - if (ie->expr->tav().mode == Addressing_SoaVariable) { + if (ie->expr->tav.mode == Addressing_SoaVariable) { // SOA Structures for slices/dynamic arrays GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); @@ -4451,8 +4451,8 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { a = lb_addr_get_ptr(p, addr); } - GB_ASSERT(is_type_array(expr->tav().type)); - return lb_addr_swizzle(a, expr->tav().type, swizzle_count, swizzle_indices); + GB_ASSERT(is_type_array(expr->tav.type)); + return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); } Selection sel = lookup_field(type, selector, false); @@ -4621,7 +4621,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_ast_node(ce, CallExpr, expr); BuiltinProcId builtin_id = BuiltinProc_Invalid; - if (ce->proc->tav().mode == Addressing_Builtin) { + if (ce->proc->tav.mode == Addressing_Builtin) { Entity *e = entity_of_node(ce->proc); if (e != nullptr) { builtin_id = cast(BuiltinProcId)e->Builtin.id; @@ -4629,7 +4629,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { builtin_id = BuiltinProc_DIRECTIVE; } } - auto const &tv = expr->tav(); + auto const &tv = expr->tav; if (builtin_id == BuiltinProc_swizzle && is_type_array(tv.type)) { // NOTE(bill, 2021-08-09): `swizzle` has some bizarre semantics so it needs to be diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 546d49027..384d29ca7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1516,7 +1516,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn BigInt bi_count = {}; big_int_from_i64(&bi_count, count); - TypeAndValue const &tv = ce->args[1]->tav(); + TypeAndValue const &tv = ce->args[1]->tav; ExactValue val = exact_value_to_integer(tv.value); GB_ASSERT(val.kind == ExactValue_Integer); BigInt *bi = &val.value_integer; @@ -2428,16 +2428,16 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_type_equal_proc: - return lb_equal_proc_for_type(p->module, ce->args[0]->tav().type); + return lb_equal_proc_for_type(p->module, ce->args[0]->tav.type); case BuiltinProc_type_hasher_proc: - return lb_hasher_proc_for_type(p->module, ce->args[0]->tav().type); + return lb_hasher_proc_for_type(p->module, ce->args[0]->tav.type); case BuiltinProc_type_map_info: - return lb_gen_map_info_ptr(p->module, ce->args[0]->tav().type); + return lb_gen_map_info_ptr(p->module, ce->args[0]->tav.type); case BuiltinProc_type_map_cell_info: - return lb_gen_map_cell_info_ptr(p->module, ce->args[0]->tav().type); + return lb_gen_map_cell_info_ptr(p->module, ce->args[0]->tav.type); case BuiltinProc_fixed_point_mul: @@ -2505,7 +2505,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_prefetch_write_data: { lbValue ptr = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_rawptr); - unsigned long long locality = cast(unsigned long long)exact_value_to_i64(ce->args[1]->tav().value); + unsigned long long locality = cast(unsigned long long)exact_value_to_i64(ce->args[1]->tav.value); unsigned long long rw = 0; unsigned long long cache = 0; switch (id) { @@ -3060,8 +3060,8 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - if (proc_expr->tav().mode == Addressing_Constant) { - ExactValue v = proc_expr->tav().value; + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; switch (v.kind) { case ExactValue_Integer: { @@ -3070,7 +3070,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); x.type = t_uintptr; x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav().type); + value = lb_emit_conv(p, x, proc_expr->tav.type); break; } case ExactValue_Pointer: @@ -3080,7 +3080,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); x.type = t_uintptr; x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav().type); + value = lb_emit_conv(p, x, proc_expr->tav.type); break; } } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index e0e991b4d..6400a8a9d 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -952,11 +952,11 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * TokenKind op = expr->BinaryExpr.op.kind; Ast *start_expr = expr->BinaryExpr.left; Ast *end_expr = expr->BinaryExpr.right; - GB_ASSERT(start_expr->tav().mode == Addressing_Constant); - GB_ASSERT(end_expr->tav().mode == Addressing_Constant); + GB_ASSERT(start_expr->tav.mode == Addressing_Constant); + GB_ASSERT(end_expr->tav.mode == Addressing_Constant); - ExactValue start = start_expr->tav().value; - ExactValue end = end_expr->tav().value; + ExactValue start = start_expr->tav.value; + ExactValue end = end_expr->tav.value; if (op != Token_RangeHalf) { // .. [start, end] (or ..=) ExactValue index = exact_value_i64(0); for (ExactValue val = start; @@ -1006,16 +1006,16 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * if (val0_type) val0_addr = lb_build_addr(p, rs->val0); if (val1_type) val1_addr = lb_build_addr(p, rs->val1); - GB_ASSERT(expr->tav().mode == Addressing_Constant); + GB_ASSERT(expr->tav.mode == Addressing_Constant); - Type *t = base_type(expr->tav().type); + Type *t = base_type(expr->tav.type); switch (t->kind) { case Type_Basic: GB_ASSERT(is_type_string(t)); { - ExactValue value = expr->tav().value; + ExactValue value = expr->tav.value; GB_ASSERT(value.kind == ExactValue_String); String str = value.value_string; Rune codepoint = 0; @@ -1109,7 +1109,7 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo if (is_ast_range(expr)) { return false; } - if (expr->tav().mode == Addressing_Type) { + if (expr->tav.mode == Addressing_Type) { GB_ASSERT(is_typeid); continue; } @@ -1209,12 +1209,12 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (switch_instr != nullptr) { lbValue on_val = {}; - if (expr->tav().mode == Addressing_Type) { + if (expr->tav.mode == Addressing_Type) { GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav().type); + lbValue e = lb_typeid(p->module, expr->tav.type); on_val = lb_emit_conv(p, e, tag.type); } else { - GB_ASSERT(expr->tav().mode == Addressing_Constant); + GB_ASSERT(expr->tav.mode == Addressing_Constant); GB_ASSERT(!is_ast_range(expr)); on_val = lb_build_expr(p, expr); @@ -1245,9 +1245,9 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs); cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); } else { - if (expr->tav().mode == Addressing_Type) { + if (expr->tav.mode == Addressing_Type) { GB_ASSERT(is_type_typeid(tag.type)); - lbValue e = lb_typeid(p->module, expr->tav().type); + lbValue e = lb_typeid(p->module, expr->tav.type); e = lb_emit_conv(p, e, tag.type); cond = lb_emit_comp(p, Token_CmpEq, tag, e); } else { @@ -1476,11 +1476,11 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { if (vd->values.count > 0) { GB_ASSERT(vd->names.count == vd->values.count); Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav().mode == Addressing_Constant || - ast_value->tav().mode == Addressing_Invalid); + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); bool allow_local = false; - value = lb_const_value(p->module, ast_value->tav().type, ast_value->tav().value, allow_local); + value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local); } Ast *ident = vd->names[i]; @@ -2068,7 +2068,7 @@ gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) { op_ += Token_Add - Token_AddEq; // Convert += to + TokenKind op = cast(TokenKind)op_; if (op == Token_CmpAnd || op == Token_CmpOr) { - Type *type = as->lhs[0]->tav().type; + Type *type = as->lhs[0]->tav.type; lbValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); lbAddr lhs = lb_build_addr(p, as->lhs[0]); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 6abcdfc04..dbed32b82 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1929,7 +1929,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, Stri gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); - auto tav = ce->args[0]->tav(); + auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name)); @@ -1939,7 +1939,7 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) ast_node(ce, CallExpr, expr); lbModule *m = p->module; - auto tav = ce->args[0]->tav(); + auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; lbAddr dst = lb_handle_objc_find_or_register_selector(p, name); @@ -1975,7 +1975,7 @@ gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); - auto tav = ce->args[0]->tav(); + auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); @@ -1985,7 +1985,7 @@ gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); lbModule *m = p->module; - auto tav = ce->args[0]->tav(); + auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; lbAddr dst = lb_handle_objc_find_or_register_class(p, name); @@ -2045,8 +2045,8 @@ gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { lbValue id = lb_handle_objc_id(p, ce->args[1]); Ast *sel_expr = ce->args[2]; - GB_ASSERT(sel_expr->tav().value.kind == ExactValue_String); - lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav().value.value_string)); + GB_ASSERT(sel_expr->tav.value.kind == ExactValue_String); + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, sel_expr->tav.value.value_string)); array_add(&args, id); array_add(&args, sel); diff --git a/src/parser.cpp b/src/parser.cpp index 42d8f62cf..436498c51 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -71,7 +71,6 @@ gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind) { Ast *node = cast(Ast *)gb_alloc(a, size); node->kind = kind; node->file_id = f ? f->id : 0; - node->tav_ = gb_alloc_item(a, TypeAndValue); global_total_node_memory_allocated.fetch_add(size); @@ -107,9 +106,6 @@ gb_internal Ast *clone_ast(Ast *node) { AstFile *f = node->thread_safe_file(); Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); - TypeAndValue *new_tav = gb_alloc_item(ast_allocator(f), TypeAndValue); - *new_tav = *node->tav_; - n->tav_ = new_tav; switch (n->kind) { default: GB_PANIC("Unhandled Ast %.*s", LIT(ast_strings[n->kind])); break; @@ -654,8 +650,8 @@ gb_internal String string_value_from_token(AstFile *f, Token const &token) { gb_internal Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *result = alloc_ast_node(f, Ast_BasicLit); result->BasicLit.token = basic_lit; - result->tav().mode = Addressing_Constant; - result->tav().value = exact_value_from_token(f, basic_lit); + result->tav.mode = Addressing_Constant; + result->tav.value = exact_value_from_token(f, basic_lit); return result; } diff --git a/src/parser.hpp b/src/parser.hpp index e3d6b42d8..7d292ffce 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -754,7 +754,7 @@ struct AstCommonStuff { u8 state_flags; u8 viral_state_flags; i32 file_id; - TypeAndValue *tav_; // TODO(bill): Make this a pointer to minimize 'Ast' size + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size }; struct Ast { @@ -762,7 +762,7 @@ struct Ast { u8 state_flags; u8 viral_state_flags; i32 file_id; - TypeAndValue *tav_; // TODO(bill): Make this a pointer to minimize 'Ast' size + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { @@ -771,9 +771,6 @@ struct Ast { #undef AST_KIND }; - gb_inline TypeAndValue &tav() const { - return *this->tav_; - } // NOTE(bill): I know I dislike methods but this is hopefully a temporary thing // for refactoring purposes -- cgit v1.2.3 From 015fe924b8f9a1d8cb78d307a4f8ef6791402bea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 12:28:38 +0000 Subject: Remove use of queues for procedure checking. --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 10 ++--- src/checker.cpp | 108 ++++++++++++++++++++-------------------------------- src/checker.hpp | 6 +-- src/thread_pool.cpp | 4 ++ 5 files changed, 52 insertions(+), 78 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 59beae56d..4e3c1b405 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -986,7 +986,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { GB_ASSERT(pl->body->kind == Ast_BlockStmt); if (!pt->is_polymorphic) { - check_procedure_later(ctx, ctx->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) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ed1ddd1f1..eb9f76547 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -417,8 +417,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E CheckerContext nctx = *old_c; - nctx.procs_to_check_queue = old_c->procs_to_check_queue; - Scope *scope = create_scope(info, base_entity->scope); scope->flags |= ScopeFlag_Proc; nctx.scope = scope; @@ -566,7 +564,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } // NOTE(bill): Check the newly generated procedure body - check_procedure_later(&nctx, proc_info); + check_procedure_later(nctx.checker, proc_info); return true; } @@ -6187,7 +6185,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op decl->where_clauses_evaluated = true; if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } return data; @@ -6225,7 +6223,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op decl->where_clauses_evaluated = true; if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } return data; @@ -9447,7 +9445,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast } pl->decl = decl; - check_procedure_later(&ctx, ctx.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(&ctx); diff --git a/src/checker.cpp b/src/checker.cpp index 1e40f04a6..30e7409f9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1195,7 +1195,6 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp GB_ASSERT(ctx->checker != nullptr); mutex_lock(&ctx->mutex); - auto *queue = ctx->procs_to_check_queue; auto type_path = ctx->type_path; array_clear(type_path); @@ -1211,7 +1210,6 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp add_curr_ast_file(ctx, file); - ctx->procs_to_check_queue = queue; ctx->untyped = untyped; mutex_unlock(&ctx->mutex); @@ -1232,7 +1230,7 @@ gb_internal void init_checker(Checker *c) { mpmc_init(&c->procs_with_deferred_to_check, a, 1<<10); // NOTE(bill): 1 Mi elements should be enough on average - mpmc_init(&c->procs_to_check_queue, heap_allocator(), 1<<20); + array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20); mpmc_init(&c->global_untyped_queue, a, 1<<20); @@ -1244,7 +1242,7 @@ gb_internal void destroy_checker(Checker *c) { destroy_checker_context(&c->builtin_ctx); - mpmc_destroy(&c->procs_to_check_queue); + array_free(&c->procs_to_check); mpmc_destroy(&c->global_untyped_queue); } @@ -1941,23 +1939,19 @@ gb_global std::atomic global_procedure_body_in_worker_queue = false; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc); -gb_internal void check_procedure_later(CheckerContext *c, ProcInfo *info) { +gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { GB_ASSERT(info != nullptr); GB_ASSERT(info->decl != nullptr); if (MULTITHREAD_CHECKER && global_procedure_body_in_worker_queue) { thread_pool_add_task(check_proc_info_worker_proc, info); } else { - if (build_context.threaded_checker && global_procedure_body_in_worker_queue) { - GB_ASSERT(c->procs_to_check_queue != nullptr); - } - - auto *queue = c->procs_to_check_queue ? c->procs_to_check_queue : &c->checker->procs_to_check_queue; - mpmc_enqueue(queue, info); + GB_ASSERT(global_procedure_body_in_worker_queue == false); + array_add(&c->procs_to_check, info); } } -gb_internal void check_procedure_later(CheckerContext *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { +gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { ProcInfo *info = gb_alloc_item(permanent_allocator(), ProcInfo); info->file = file; info->token = token; @@ -4677,11 +4671,7 @@ struct CollectEntityWorkerData { gb_global CollectEntityWorkerData *collect_entity_worker_data; gb_internal WORKER_TASK_PROC(check_collect_entities_all_worker_proc) { - isize thread_idx = 0; - if (current_thread) { - thread_idx = current_thread->idx; - } - CollectEntityWorkerData *wd = &collect_entity_worker_data[thread_idx]; + CollectEntityWorkerData *wd = &collect_entity_worker_data[current_thread_index()]; Checker *c = wd->c; CheckerContext *ctx = &wd->ctx; @@ -4738,10 +4728,8 @@ gb_internal void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *p } gb_internal WORKER_TASK_PROC(check_export_entities_worker_proc) { - isize thread_idx = current_thread ? current_thread->idx : 0; - AstPackage *pkg = (AstPackage *)data; - auto *wd = &collect_entity_worker_data[thread_idx]; + auto *wd = &collect_entity_worker_data[current_thread_index()]; check_export_entities_in_pkg(&wd->ctx, pkg, &wd->untyped); return 0; } @@ -5069,7 +5057,7 @@ gb_internal void calculate_global_init_order(Checker *c) { } -gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped, ProcBodyQueue *procs_to_check_queue) { +gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { if (pi == nullptr) { return false; } @@ -5085,17 +5073,16 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u } return true; } + if (e != nullptr && (e->flags & EntityFlag_ProcBodyChecked) != 0) { + GB_ASSERT(pi->decl->proc_checked); + return true; + } + pi->decl->proc_checked = true; + if (e != nullptr) { + e->flags |= EntityFlag_ProcBodyChecked; + } } - CheckerContext ctx = make_checker_context(c); - defer (destroy_checker_context(&ctx)); - reset_checker_context(&ctx, pi->file, untyped); - ctx.decl = pi->decl; - - GB_ASSERT(procs_to_check_queue != nullptr || MULTITHREAD_CHECKER); - - ctx.procs_to_check_queue = procs_to_check_queue; - GB_ASSERT(pi->type->kind == Type_Proc); TypeProc *pt = &pi->type->Proc; String name = pi->token.string; @@ -5116,6 +5103,12 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u } } + + CheckerContext ctx = make_checker_context(c); + defer (destroy_checker_context(&ctx)); + reset_checker_context(&ctx, pi->file, untyped); + ctx.decl = pi->decl; + bool bounds_check = (pi->tags & ProcTag_bounds_check) != 0; bool no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0; @@ -5138,24 +5131,14 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u ctx.state_flags &= ~StateFlag_type_assert; } - if (pi->body != nullptr && e != nullptr) { - GB_ASSERT((e->flags & EntityFlag_ProcBodyChecked) == 0); - } - check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); - MUTEX_GUARD_BLOCK(&pi->decl->proc_checked_mutex) { - if (e != nullptr) { - e->flags |= EntityFlag_ProcBodyChecked; - } - pi->decl->proc_checked = true; - } add_untyped_expressions(&c->info, ctx.untyped); return true; } GB_STATIC_ASSERT(sizeof(isize) == sizeof(void *)); -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped); +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); gb_internal void check_unchecked_bodies(Checker *c) { // NOTE(2021-02-26, bill): Sanity checker @@ -5193,15 +5176,13 @@ gb_internal void check_unchecked_bodies(Checker *c) { } debugf("unchecked: %.*s\n", LIT(e->token.string)); - mpmc_enqueue(&c->procs_to_check_queue, pi); + array_add(&c->procs_to_check, pi); } } - auto *q = &c->procs_to_check_queue; - ProcInfo *pi = nullptr; - while (mpmc_dequeue(q, &pi)) { + for (ProcInfo *pi : c->procs_to_check) { Entity *e = pi->decl->entity; - if (consume_proc_info_queue(c, pi, q, &untyped)) { + if (consume_proc_info_queue(c, pi, &untyped)) { add_dependency_to_set(c, e); GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); } @@ -5245,7 +5226,7 @@ gb_internal void check_test_procedures(Checker *c) { gb_global std::atomic total_bodies_checked; -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue *q, UntypedExprInfoMap *untyped) { +gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { GB_ASSERT(pi->decl != nullptr); if (pi->decl->parent && pi->decl->parent->entity) { Entity *parent = pi->decl->parent->entity; @@ -5253,14 +5234,14 @@ gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, ProcBodyQueue // This is prevent any possible race conditions in evaluation when multithreaded // NOTE(bill): In single threaded mode, this should never happen if (parent->kind == Entity_Procedure && (parent->flags & EntityFlag_ProcBodyChecked) == 0) { - mpmc_enqueue(q, pi); + check_procedure_later(c, pi); return false; } } if (untyped) { map_clear(untyped); } - bool ok = check_proc_info(c, pi, untyped, q); + bool ok = check_proc_info(c, pi, untyped); total_bodies_checked.fetch_add(1, std::memory_order_relaxed); return ok; } @@ -5273,12 +5254,9 @@ struct CheckProcedureBodyWorkerData { gb_global CheckProcedureBodyWorkerData *check_procedure_bodies_worker_data; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { - isize thread_idx = 0; - if (current_thread) { - thread_idx = current_thread->idx; - } - UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[thread_idx].untyped; - Checker *c = check_procedure_bodies_worker_data[thread_idx].c; + auto *wd = &check_procedure_bodies_worker_data[current_thread_index()]; + UntypedExprInfoMap *untyped = &wd->untyped; + Checker *c = wd->c; ProcInfo *pi = cast(ProcInfo *)data; @@ -5294,7 +5272,7 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { } } map_clear(untyped); - bool ok = check_proc_info(c, pi, untyped, nullptr); + bool ok = check_proc_info(c, pi, untyped); total_bodies_checked.fetch_add(1, std::memory_order_relaxed); return !ok; } @@ -5321,13 +5299,11 @@ gb_internal void check_procedure_bodies(Checker *c) { }); if (thread_count == 1) { - auto *this_queue = &c->procs_to_check_queue; - UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[0].untyped; - - for (ProcInfo *pi = nullptr; mpmc_dequeue(this_queue, &pi); /**/) { - consume_proc_info_queue(c, pi, this_queue, untyped); + for_array(i, c->procs_to_check) { + consume_proc_info_queue(c, c->procs_to_check[i], untyped); } + array_clear(&c->procs_to_check); debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); return; @@ -5335,12 +5311,12 @@ gb_internal void check_procedure_bodies(Checker *c) { global_procedure_body_in_worker_queue = true; - for (ProcInfo *pi = nullptr; mpmc_dequeue(&c->procs_to_check_queue, &pi); /**/) { - thread_pool_add_task(check_proc_info_worker_proc, pi); + isize prev_procs_to_check_count = c->procs_to_check.count; + for_array(i, c->procs_to_check) { + thread_pool_add_task(check_proc_info_worker_proc, c->procs_to_check[i]); } - - isize global_remaining = c->procs_to_check_queue.count.load(std::memory_order_relaxed); - GB_ASSERT(global_remaining == 0); + GB_ASSERT(prev_procs_to_check_count == c->procs_to_check.count); + array_clear(&c->procs_to_check); thread_pool_wait(); diff --git a/src/checker.hpp b/src/checker.hpp index 1d6019b79..eaad1fa63 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -418,8 +418,6 @@ struct CheckerContext { Scope * polymorphic_scope; Ast *assignment_lhs_hint; - - ProcBodyQueue *procs_to_check_queue; }; @@ -430,9 +428,7 @@ struct Checker { CheckerContext builtin_ctx; MPMCQueue procs_with_deferred_to_check; - - ProcBodyQueue procs_to_check_queue; - Semaphore procs_to_check_semaphore; + Array procs_to_check; // TODO(bill): Technically MPSC queue MPMCQueue global_untyped_queue; diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 9ac1af039..939d3c533 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -21,6 +21,10 @@ struct ThreadPool { Futex tasks_left; }; +gb_internal isize current_thread_index(void) { + return current_thread ? current_thread->idx : 0; +} + gb_internal void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_name) { pool->allocator = a; slice_init(&pool->threads, a, thread_count + 1); -- cgit v1.2.3 From 529383f5b17d74f66bebb8679820a69476635b6a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 15:30:04 +0000 Subject: Correct a race condition when checking the procedure body --- src/build_settings.cpp | 1 + src/check_decl.cpp | 25 ++--- src/check_expr.cpp | 23 ++++- src/checker.cpp | 224 ++++++++++++++++++++++++++++++++++--------- src/checker.hpp | 21 +++- src/llvm_backend.cpp | 6 ++ src/llvm_backend.hpp | 1 + src/llvm_backend_expr.cpp | 6 +- src/llvm_backend_general.cpp | 5 +- src/llvm_backend_proc.cpp | 3 +- src/llvm_backend_stmt.cpp | 6 +- src/main.cpp | 5 + 12 files changed, 260 insertions(+), 66 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 97b512b81..f59b5c0f7 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -291,6 +291,7 @@ struct BuildContext { bool show_error_line; bool ignore_lazy; + bool ignore_llvm_build; bool use_subsystem_windows; bool ignore_microsoft_magic; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 4e3c1b405..8f95c1a49 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1419,9 +1419,9 @@ struct ProcUsingVar { }; -gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { +gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) { if (body == nullptr) { - return; + return false; } GB_ASSERT(body->kind == Ast_BlockStmt); @@ -1502,7 +1502,7 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) { Entity *e = using_entities[i].e; Entity *uvar = using_entities[i].uvar; - Entity *prev = scope_insert(ctx->scope, uvar, false); + Entity *prev = scope_insert_no_mutex(ctx->scope, uvar); if (prev != nullptr) { error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string)); @@ -1514,7 +1514,7 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated); if (!where_clause_ok) { // NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed - return; + return false; } check_open_scope(ctx, body); @@ -1526,7 +1526,12 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de // NOTE(bill): Don't err here } - GB_ASSERT(decl->defer_use_checked == false); + GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked); + if (decl->defer_use_checked) { + GB_ASSERT(is_type_polymorphic(type, true)); + error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string)); + GB_ASSERT(decl->defer_use_checked == false); + } check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); @@ -1575,10 +1580,8 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de if (decl->parent != nullptr) { Scope *ps = decl->parent->scope; if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - return; - } else { - mutex_lock(&ctx->info->deps_mutex); - + return true; + } else MUTEX_GUARD_BLOCK(&ctx->info->deps_mutex) { // NOTE(bill): Add the dependencies from the procedure literal (lambda) // But only at the procedure level for (auto const &entry : decl->deps) { @@ -1589,8 +1592,8 @@ gb_internal void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de Type *t = entry.ptr; ptr_set_add(&decl->parent->type_info_deps, t); } - - mutex_unlock(&ctx->info->deps_mutex); } } + + return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index eb9f76547..5445e73c7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -86,7 +86,6 @@ gb_internal Entity * find_polymorphic_record_entity (CheckerContext *c, Type *or gb_internal void check_not_tuple (CheckerContext *c, Operand *operand); gb_internal void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gb_internal gbString expr_to_string (Ast *expression); -gb_internal void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, Ast *body); gb_internal void update_untyped_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); gb_internal bool check_is_terminating (Ast *node, String const &label); gb_internal bool check_has_break (Ast *stmt, String const &label, bool implicit); @@ -478,6 +477,22 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E if (poly_proc_data) { poly_proc_data->gen_entity = other; } + + DeclInfo *decl = other->decl_info; + if (decl->proc_checked_state != ProcCheckedState_Checked) { + ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); + proc_info->file = other->file; + proc_info->token = other->token; + proc_info->decl = decl; + proc_info->type = other->type; + proc_info->body = decl->proc_lit->ProcLit.body; + proc_info->tags = other->Procedure.tags;; + proc_info->generated_from_polymorphic = true; + proc_info->poly_def_node = poly_def_node; + + check_procedure_later(nctx.checker, proc_info); + } + return true; } } @@ -518,7 +533,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E d->gen_proc_type = final_proc_type; d->type_expr = pl->type; d->proc_lit = proc_lit; - d->proc_checked = false; + d->proc_checked_state = ProcCheckedState_Unchecked; + d->defer_use_checked = false; Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); entity->identifier = ident; @@ -528,7 +544,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->scope = scope->parent; entity->file = base_entity->file; entity->pkg = base_entity->pkg; - entity->flags &= ~EntityFlag_ProcBodyChecked; + entity->flags = 0; + d->entity = entity; AstFile *file = nullptr; { diff --git a/src/checker.cpp b/src/checker.cpp index d3a9c3d2c..f4c9b6822 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1,3 +1,5 @@ +#define DEBUG_CHECK_ALL_PROCEDURES 1 + #include "entity.cpp" #include "types.cpp" @@ -179,6 +181,7 @@ gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { + gb_zero_item(d); d->parent = parent; d->scope = scope; ptr_set_init(&d->deps, heap_allocator()); @@ -438,9 +441,44 @@ gb_internal Entity *scope_lookup(Scope *s, String const &name) { return entity; } +gb_internal Entity *scope_insert_with_name_no_mutex(Scope *s, String const &name, Entity *entity) { + if (name == "") { + return nullptr; + } + StringHashKey key = string_hash_string(name); + Entity **found = nullptr; + Entity *result = nullptr; + + found = string_map_get(&s->elements, key); + + if (found) { + if (entity != *found) { + result = *found; + } + goto end; + } + if (s->parent != nullptr && (s->parent->flags & ScopeFlag_Proc) != 0) { + found = string_map_get(&s->parent->elements, key); + if (found) { + if ((*found)->flags & EntityFlag_Result) { + if (entity != *found) { + result = *found; + } + goto end; + } + } + } + + string_map_set(&s->elements, key, entity); + if (entity->scope == nullptr) { + entity->scope = s; + } +end:; + return result; +} -gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity, bool use_mutex=true) { +gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity *entity) { if (name == "") { return nullptr; } @@ -448,9 +486,8 @@ gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity Entity **found = nullptr; Entity *result = nullptr; - if (use_mutex) mutex_lock(&s->mutex); - defer (if (use_mutex) mutex_unlock(&s->mutex)); - + MUTEX_GUARD(&s->mutex); + found = string_map_get(&s->elements, key); if (found) { @@ -479,9 +516,14 @@ end:; return result; } -gb_internal Entity *scope_insert(Scope *s, Entity *entity, bool use_mutex) { +gb_internal Entity *scope_insert(Scope *s, Entity *entity) { String name = entity->token.string; - return scope_insert_with_name(s, name, entity, use_mutex); + return scope_insert_with_name(s, name, entity); +} + +gb_internal Entity *scope_insert_no_mutex(Scope *s, Entity *entity) { + String name = entity->token.string; + return scope_insert_with_name_no_mutex(s, name, entity); } @@ -1135,6 +1177,9 @@ gb_internal void init_checker_info(CheckerInfo *i) { map_init(&i->objc_msgSend_types, a); string_map_init(&i->load_file_cache, a); + + array_init(&i->all_procedures, heap_allocator()); + } gb_internal void destroy_checker_info(CheckerInfo *i) { @@ -1934,6 +1979,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { gb_global std::atomic global_procedure_body_in_worker_queue = false; +gb_global std::atomic global_after_checking_procedure_bodies = false; gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc); @@ -1941,12 +1987,24 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { GB_ASSERT(info != nullptr); GB_ASSERT(info->decl != nullptr); - if (global_procedure_body_in_worker_queue) { + if (global_after_checking_procedure_bodies) { + Entity *e = info->decl->entity; + debugf("CHECK PROCEDURE LATER! %.*s :: %s {...}\n", LIT(e->token.string), type_to_string(e->type)); + } + + if (global_procedure_body_in_worker_queue.load()) { thread_pool_add_task(check_proc_info_worker_proc, info); } else { - GB_ASSERT(global_procedure_body_in_worker_queue == false); array_add(&c->procs_to_check, info); } + + if (DEBUG_CHECK_ALL_PROCEDURES) { + MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) { + GB_ASSERT(info != nullptr); + GB_ASSERT(info->decl != nullptr); + array_add(&c->info.all_procedures, info); + } + } } gb_internal void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, Ast *body, u64 tags) { @@ -5010,24 +5068,26 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u if (pi->type == nullptr) { return false; } - Entity *e = pi->decl->entity; - MUTEX_GUARD_BLOCK(&pi->decl->proc_checked_mutex) { - if (pi->decl->proc_checked) { - if (e != nullptr) { - GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); - } - return true; - } - if (e != nullptr && (e->flags & EntityFlag_ProcBodyChecked) != 0) { - GB_ASSERT(pi->decl->proc_checked); - return true; + MUTEX_GUARD(&pi->decl->proc_checked_mutex); + + Entity *e = pi->decl->entity; + switch (pi->decl->proc_checked_state.load()) { + case ProcCheckedState_InProgress: + if (e) { + GB_ASSERT(global_procedure_body_in_worker_queue.load()); } - pi->decl->proc_checked = true; + return false; + case ProcCheckedState_Checked: if (e != nullptr) { - e->flags |= EntityFlag_ProcBodyChecked; + GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); } + return true; + case ProcCheckedState_Unchecked: + // okay + break; } + pi->decl->proc_checked_state.store(ProcCheckedState_InProgress); GB_ASSERT(pi->type->kind == Type_Proc); TypeProc *pt = &pi->type->Proc; @@ -5039,17 +5099,21 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u token = ast_token(pi->poly_def_node); } error(token, "Unspecialized polymorphic procedure '%.*s'", LIT(name)); + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); return false; } if (pt->is_polymorphic && pt->is_poly_specialized) { + Entity *e = pi->decl->entity; + GB_ASSERT(e != nullptr); if ((e->flags & EntityFlag_Used) == 0) { // NOTE(bill, 2019-08-31): It was never used, don't check + // NOTE(bill, 2023-01-02): This may need to be checked again if it is used elsewhere? + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); return false; } } - CheckerContext ctx = make_checker_context(c); defer (destroy_checker_context(&ctx)); reset_checker_context(&ctx, pi->file, untyped); @@ -5077,14 +5141,34 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u ctx.state_flags &= ~StateFlag_type_assert; } - check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); + bool body_was_checked = check_proc_body(&ctx, pi->token, pi->decl, pi->type, pi->body); + + if (body_was_checked) { + pi->decl->proc_checked_state.store(ProcCheckedState_Checked); + if (pi->body) { + Entity *e = pi->decl->entity; + if (e != nullptr) { + e->flags |= EntityFlag_ProcBodyChecked; + } + } + } else { + pi->decl->proc_checked_state.store(ProcCheckedState_Unchecked); + if (pi->body) { + Entity *e = pi->decl->entity; + if (e != nullptr) { + e->flags &= ~EntityFlag_ProcBodyChecked; + } + } + } + add_untyped_expressions(&c->info, ctx.untyped); + return true; } GB_STATIC_ASSERT(sizeof(isize) == sizeof(void *)); -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); +gb_internal bool consume_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped); gb_internal void check_unchecked_bodies(Checker *c) { // NOTE(2021-02-26, bill): Sanity checker @@ -5092,10 +5176,15 @@ gb_internal void check_unchecked_bodies(Checker *c) { // even ones which should not exist, due to the multithreaded nature of the parser // HACK TODO(2021-02-26, bill): Actually fix this race condition + GB_ASSERT(c->procs_to_check.count == 0); + UntypedExprInfoMap untyped = {}; map_init(&untyped, heap_allocator()); defer (map_destroy(&untyped)); + // use the `procs_to_check` array + global_procedure_body_in_worker_queue = false; + for (auto const &entry : c->info.minimum_dependency_set) { Entity *e = entry.ptr; if (e == nullptr || e->kind != Entity_Procedure) { @@ -5122,19 +5211,22 @@ gb_internal void check_unchecked_bodies(Checker *c) { } debugf("unchecked: %.*s\n", LIT(e->token.string)); - array_add(&c->procs_to_check, pi); + check_procedure_later(c, pi); } } - for (ProcInfo *pi : c->procs_to_check) { - Entity *e = pi->decl->entity; - if (consume_proc_info_queue(c, pi, &untyped)) { - add_dependency_to_set(c, e); - GB_ASSERT(e->flags & EntityFlag_ProcBodyChecked); + if (!global_procedure_body_in_worker_queue) { + for_array(i, c->procs_to_check) { + ProcInfo *pi = c->procs_to_check[i]; + consume_proc_info(c, pi, &untyped); } + array_clear(&c->procs_to_check); + } else { + thread_pool_wait(); } - thread_pool_wait(); + global_procedure_body_in_worker_queue = false; + global_after_checking_procedure_bodies = true; } gb_internal void check_test_procedures(Checker *c) { @@ -5172,8 +5264,15 @@ gb_internal void check_test_procedures(Checker *c) { gb_global std::atomic total_bodies_checked; -gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { +gb_internal bool consume_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) { GB_ASSERT(pi->decl != nullptr); + switch (pi->decl->proc_checked_state.load()) { + case ProcCheckedState_InProgress: + return false; + case ProcCheckedState_Checked: + return true; + } + if (pi->decl->parent && pi->decl->parent->entity) { Entity *parent = pi->decl->parent->entity; // NOTE(bill): Only check a nested procedure if its parent's body has been checked first @@ -5187,9 +5286,11 @@ gb_internal bool consume_proc_info_queue(Checker *c, ProcInfo *pi, UntypedExprIn if (untyped) { map_clear(untyped); } - bool ok = check_proc_info(c, pi, untyped); - total_bodies_checked.fetch_add(1, std::memory_order_relaxed); - return ok; + if (check_proc_info(c, pi, untyped)) { + total_bodies_checked.fetch_add(1, std::memory_order_relaxed); + return true; + } + return false; } struct CheckProcedureBodyWorkerData { @@ -5218,9 +5319,11 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { } } map_clear(untyped); - bool ok = check_proc_info(c, pi, untyped); - total_bodies_checked.fetch_add(1, std::memory_order_relaxed); - return !ok; + if (check_proc_info(c, pi, untyped)) { + total_bodies_checked.fetch_add(1, std::memory_order_relaxed); + return 0; + } + return 1; } @@ -5247,7 +5350,7 @@ gb_internal void check_procedure_bodies(Checker *c) { if (thread_count == 1) { UntypedExprInfoMap *untyped = &check_procedure_bodies_worker_data[0].untyped; for_array(i, c->procs_to_check) { - consume_proc_info_queue(c, c->procs_to_check[i], untyped); + consume_proc_info(c, c->procs_to_check[i], untyped); } array_clear(&c->procs_to_check); @@ -5266,9 +5369,6 @@ gb_internal void check_procedure_bodies(Checker *c) { thread_pool_wait(); - debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); - - global_procedure_body_in_worker_queue = false; } gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) { @@ -5662,9 +5762,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check test procedures"); check_test_procedures(c); - TIME_SECTION("check bodies have all been checked"); - check_unchecked_bodies(c); - TIME_SECTION("add type info for type definitions"); add_type_info_for_type_definitions(c); check_merge_queues_into_arrays(c); @@ -5672,6 +5769,12 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("generate minimum dependency set"); generate_minimum_dependency_set(c, c->info.entry_point); + TIME_SECTION("check bodies have all been checked"); + check_unchecked_bodies(c); + + check_merge_queues_into_arrays(c); + + TIME_SECTION("check entry point"); if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) { Scope *s = c->info.init_scope; @@ -5694,11 +5797,39 @@ gb_internal void check_parsed_files(Checker *c) { } } + thread_pool_wait(); + GB_ASSERT(c->procs_to_check.count == 0); + + if (DEBUG_CHECK_ALL_PROCEDURES) { + UntypedExprInfoMap untyped = {}; + map_init(&untyped, heap_allocator()); + defer (map_destroy(&untyped)); + + for_array(i, c->info.all_procedures) { + ProcInfo *pi = c->info.all_procedures[i]; + GB_ASSERT(pi != nullptr); + GB_ASSERT(pi->decl != nullptr); + Entity *e = pi->decl->entity; + auto proc_checked_state = pi->decl->proc_checked_state.load(); + if (e && ((e->flags & EntityFlag_ProcBodyChecked) == 0)) { + if ((e->flags & EntityFlag_Used) != 0) { + debugf("%.*s :: %s\n", LIT(e->token.string), type_to_string(e->type)); + debugf("proc body unchecked\n"); + debugf("Checked State: %s\n\n", ProcCheckedState_strings[proc_checked_state]); + + consume_proc_info(c, pi, &untyped); + } + } + } + } + + debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); + TIME_SECTION("check unique package names"); check_unique_package_names(c); - TIME_SECTION("sanity checks"); + check_merge_queues_into_arrays(c); GB_ASSERT(c->info.entity_queue.count.load(std::memory_order_relaxed) == 0); GB_ASSERT(c->info.definition_queue.count.load(std::memory_order_relaxed) == 0); @@ -5717,5 +5848,6 @@ gb_internal void check_parsed_files(Checker *c) { } } + TIME_SECTION("type check finish"); } diff --git a/src/checker.hpp b/src/checker.hpp index eaad1fa63..37aff41b1 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -142,6 +142,20 @@ typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc); gb_internal void check_decl_attributes(CheckerContext *c, Array const &attributes, DeclAttributeProc *proc, AttributeContext *ac); +enum ProcCheckedState : u8 { + ProcCheckedState_Unchecked, + ProcCheckedState_InProgress, + ProcCheckedState_Checked, + + ProcCheckedState_COUNT +}; + +char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { + "Unchecked", + "In Progress", + "Checked", +}; + // DeclInfo is used to store information of certain declarations to allow for "any order" usage struct DeclInfo { DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment @@ -157,7 +171,7 @@ struct DeclInfo { Type * gen_proc_type; // Precalculated bool is_using; bool where_clauses_evaluated; - bool proc_checked; + std::atomic proc_checked_state; BlockingMutex proc_checked_mutex; isize defer_used; bool defer_use_checked; @@ -375,6 +389,9 @@ struct CheckerInfo { BlockingMutex load_file_mutex; StringMap load_file_cache; + + BlockingMutex all_procedures_mutex;; + Array all_procedures; }; struct CheckerContext { @@ -458,7 +475,7 @@ gb_internal Entity *entity_of_node(Ast *expr); gb_internal Entity *scope_lookup_current(Scope *s, String const &name); gb_internal Entity *scope_lookup (Scope *s, String const &name); gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_); -gb_internal Entity *scope_insert (Scope *s, Entity *entity, bool use_mutex=true); +gb_internal Entity *scope_insert (Scope *s, Entity *entity); gb_internal void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1c401552e..3e62f678a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2255,6 +2255,12 @@ gb_internal void lb_generate_code(lbGenerator *gen) { } } + if (build_context.ignore_llvm_build) { + gb_printf_err("LLVM SUCCESS!\n"); + gb_exit(1); + return; + } + if (do_threading && non_empty_module_count > 1) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 9f7caa3bb..50fb5701f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -301,6 +301,7 @@ struct lbProcedure { lbBlock * curr_block; lbTargetList * target_list; PtrMap direct_parameters; + PtrMap local_entity_map; Ast *curr_stmt; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index d574caf4c..28a68b065 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3404,7 +3404,11 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp lbValue v = {}; - lbValue *found = map_get(&p->module->values, e); + lbValue *found = nullptr; + found = map_get(&p->local_entity_map, e); + if (found == nullptr) { + found = map_get(&p->module->values, e); + } if (found) { v = *found; } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 0508c6171..940c94a13 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2714,7 +2714,6 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { return g; } } - GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); return {}; } @@ -2845,6 +2844,10 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero lb_mem_zero_ptr(p, ptr, type, alignment); } + if (e != nullptr) { + map_set(&p->local_entity_map, e, val); + } + return lb_addr(val); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 384d29ca7..9691afebc 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -68,7 +68,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); if (!entity->Procedure.is_foreign) { - GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type)); + GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s (was parapoly: %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true)); } String link_name = {}; @@ -487,6 +487,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters, heap_allocator()); + map_init(&p->local_entity_map, heap_allocator()); GB_ASSERT(p->type != nullptr); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 6400a8a9d..cdfb28aa7 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1531,6 +1531,9 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { lbValue global_val = {global, alloc_type_pointer(e->type)}; lb_add_entity(p->module, e, global_val); lb_add_member(p->module, mangled_name, global_val); + if (e) { + map_set(&p->local_entity_map, e, global_val); + } } } gb_internal void lb_append_tuple_values(lbProcedure *p, Array *dst_values, lbValue src_value) { @@ -2188,9 +2191,10 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { for_array(i, vd->names) { Ast *name = vd->names[i]; if (!is_blank_ident(name)) { + GB_ASSERT(name->kind == Ast_Ident); Entity *e = entity_of_node(name); TokenPos pos = ast_token(name).pos; - GB_ASSERT_MSG(e != nullptr, "%s", token_pos_to_string(pos)); + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); if (e->flags & EntityFlag_Static) { // NOTE(bill): If one of the entities is static, they all are is_static = true; diff --git a/src/main.cpp b/src/main.cpp index 3ad0e160f..42d6f8e87 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -660,6 +660,7 @@ enum BuildFlagKind { // internal use only BuildFlag_InternalIgnoreLazy, + BuildFlag_InternalIgnoreLLVMBuild, #if defined(GB_SYSTEM_WINDOWS) BuildFlag_IgnoreVsSearch, @@ -832,6 +833,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); #if defined(GB_SYSTEM_WINDOWS) add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build); @@ -1491,6 +1493,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalIgnoreLazy: build_context.ignore_lazy = true; break; + case BuildFlag_InternalIgnoreLLVMBuild: + build_context.ignore_llvm_build = true; + break; #if defined(GB_SYSTEM_WINDOWS) case BuildFlag_IgnoreVsSearch: { GB_ASSERT(value.kind == ExactValue_Invalid); -- cgit v1.2.3 From c293f5b7ebc3b733e996a97c6e32d678f13b3ee5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 16:56:05 +0000 Subject: Remove unneeded mutex --- src/check_expr.cpp | 33 +++++++++++++++++---------------- src/checker.hpp | 7 ++++++- src/common_memory.cpp | 18 ++++++------------ src/llvm_backend_stmt.cpp | 5 ++--- src/main.cpp | 3 +-- src/threading.cpp | 17 +++++++++-------- 6 files changed, 41 insertions(+), 42 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5445e73c7..f47361c27 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -193,8 +193,7 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b GB_ASSERT(e->kind == Entity_TypeName); GB_ASSERT(e->TypeName.objc_metadata != nullptr); auto *objc_metadata = e->TypeName.objc_metadata; - mutex_lock(objc_metadata->mutex); - defer (mutex_unlock(objc_metadata->mutex)); + MUTEX_GUARD(objc_metadata->mutex); StringSet set = {}; string_set_init(&set, heap_allocator()); @@ -369,8 +368,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E GB_ASSERT(dst == nullptr); } - mutex_lock(&info->gen_procs_mutex); - defer (mutex_unlock(&info->gen_procs_mutex)); + // MUTEX_GUARD(&info->gen_procs_mutex); if (!src->Proc.is_polymorphic || src->Proc.is_poly_specialized) { return false; @@ -436,11 +434,14 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return false; } - auto *found_gen_procs = map_get(&info->gen_procs, base_entity->identifier.load()); + GenProcsData *found_gen_procs = nullptr; + + MUTEX_GUARD(&info->gen_procs_mutex); + + found_gen_procs = map_get(&info->gen_procs, base_entity->identifier.load()); if (found_gen_procs) { - auto procs = *found_gen_procs; - for_array(i, procs) { - Entity *other = procs[i]; + MUTEX_GUARD(&found_gen_procs->mutex); + for (Entity *other : found_gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { if (poly_proc_data) { @@ -463,15 +464,13 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E // LEAK TODO(bill): Cloning this AST may be leaky Ast *cloned_proc_type_node = clone_ast(pt->node); success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands); - if (!success) { return false; } if (found_gen_procs) { - auto procs = *found_gen_procs; - for_array(i, procs) { - Entity *other = procs[i]; + MUTEX_GUARD(&found_gen_procs->mutex); + for (Entity *other : found_gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { if (poly_proc_data) { @@ -567,11 +566,13 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E proc_info->poly_def_node = poly_def_node; if (found_gen_procs) { - array_add(found_gen_procs, entity); + MUTEX_GUARD(&found_gen_procs->mutex); + array_add(&found_gen_procs->procs, entity); } else { - auto array = array_make(heap_allocator()); - array_add(&array, entity); - map_set(&info->gen_procs, base_entity->identifier.load(), array); + GenProcsData gen_proc_data = {}; + gen_proc_data.procs = array_make(heap_allocator()); + array_add(&gen_proc_data.procs, entity); + map_set(&info->gen_procs, base_entity->identifier.load(), gen_proc_data); } if (poly_proc_data) { diff --git a/src/checker.hpp b/src/checker.hpp index 37aff41b1..56f8707d3 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -311,6 +311,11 @@ struct LoadFileCache { StringMap hashes; }; +struct GenProcsData { + Array procs; + BlockingMutex mutex; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -360,7 +365,7 @@ struct CheckerInfo { RecursiveMutex gen_procs_mutex; RecursiveMutex gen_types_mutex; - PtrMap > gen_procs; // Key: Ast * | Identifier -> Entity + PtrMap gen_procs; // Key: Ast * | Identifier -> Entity PtrMap > gen_types; BlockingMutex type_info_mutex; // NOT recursive diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 2022554cf..cdf2281fe 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -37,7 +37,6 @@ gb_internal gb_inline void *align_formula_ptr(void *ptr, isize align) { gb_global BlockingMutex global_memory_block_mutex; -gb_global BlockingMutex global_memory_allocator_mutex; gb_internal void platform_virtual_memory_init(void); @@ -55,9 +54,9 @@ struct MemoryBlock { }; struct Arena { - MemoryBlock *curr_block; - isize minimum_block_size; - bool ignore_mutex; + MemoryBlock * curr_block; + isize minimum_block_size; + BlockingMutex mutex; }; enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll }; @@ -83,10 +82,7 @@ gb_internal isize arena_align_forward_offset(Arena *arena, isize alignment) { gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { GB_ASSERT(gb_is_power_of_two(alignment)); - BlockingMutex *mutex = &global_memory_allocator_mutex; - if (!arena->ignore_mutex) { - mutex_lock(mutex); - } + mutex_lock(&arena->mutex); isize size = 0; if (arena->curr_block != nullptr) { @@ -113,9 +109,7 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { curr_block->used += size; GB_ASSERT(curr_block->used <= curr_block->size); - if (!arena->ignore_mutex) { - mutex_unlock(mutex); - } + mutex_unlock(&arena->mutex); // NOTE(bill): memory will be zeroed by default due to virtual memory return ptr; @@ -304,7 +298,7 @@ gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) { } -gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE, true}; +gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE}; gb_internal gbAllocator permanent_allocator() { return arena_allocator(&permanent_arena); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 06abebc78..8742423a5 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -57,9 +57,8 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) if (pl->body != nullptr) { auto *found = map_get(&info->gen_procs, ident); if (found) { - auto procs = *found; - for_array(i, procs) { - Entity *e = procs[i]; + MUTEX_GUARD(&found->mutex); + for (Entity *e : found->procs) { if (!ptr_set_exists(min_dep_set, e)) { continue; } diff --git a/src/main.cpp b/src/main.cpp index 42d6f8e87..ad9d6b0ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,8 +17,7 @@ gb_global ThreadPool global_thread_pool; gb_internal void init_global_thread_pool(void) { isize thread_count = gb_max(build_context.thread_count, 1); - isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work - thread_pool_init(&global_thread_pool, permanent_allocator(), worker_count, "ThreadPoolWorker"); + thread_pool_init(&global_thread_pool, permanent_allocator(), thread_count, "ThreadPoolWorker"); } gb_internal bool thread_pool_add_task(WorkerTaskProc *proc, void *data) { return thread_pool_add_task(&global_thread_pool, proc, data); diff --git a/src/threading.cpp b/src/threading.cpp index 4c7aa8f92..c5db5d1b4 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -77,22 +77,23 @@ gb_internal void yield_process(void); struct MutexGuard { - MutexGuard() = delete; + MutexGuard() = delete; MutexGuard(MutexGuard const &) = delete; + MutexGuard(MutexGuard &&) = delete; - MutexGuard(BlockingMutex *bm) : bm{bm} { + explicit MutexGuard(BlockingMutex *bm) noexcept : bm{bm} { mutex_lock(this->bm); } - MutexGuard(RecursiveMutex *rm) : rm{rm} { + explicit MutexGuard(RecursiveMutex *rm) noexcept : rm{rm} { mutex_lock(this->rm); } - MutexGuard(BlockingMutex &bm) : bm{&bm} { + explicit MutexGuard(BlockingMutex &bm) noexcept : bm{&bm} { mutex_lock(this->bm); } - MutexGuard(RecursiveMutex &rm) : rm{&rm} { + explicit MutexGuard(RecursiveMutex &rm) noexcept : rm{&rm} { mutex_lock(this->rm); } - ~MutexGuard() { + ~MutexGuard() noexcept { if (this->bm) { mutex_unlock(this->bm); } else if (this->rm) { @@ -100,14 +101,14 @@ struct MutexGuard { } } - operator bool() const { return true; } + operator bool() const noexcept { return true; } BlockingMutex *bm; RecursiveMutex *rm; }; #define MUTEX_GUARD_BLOCK(m) if (MutexGuard GB_DEFER_3(_mutex_guard_){m}) -#define MUTEX_GUARD(m) MutexGuard GB_DEFER_3(_mutex_guard_){m} +#define MUTEX_GUARD(m) mutex_lock(m); defer (mutex_unlock(m)) struct RecursiveMutex { -- cgit v1.2.3 From 6bd3a9d422d0567ead89e2465f46068d52f34f20 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 22:23:49 +0000 Subject: Be very explicit where the gen_procs_mutex can be unlock --- src/check_expr.cpp | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f47361c27..b40c48459 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -436,14 +436,19 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E GenProcsData *found_gen_procs = nullptr; - MUTEX_GUARD(&info->gen_procs_mutex); + // @@GPM + mutex_lock(&info->gen_procs_mutex); found_gen_procs = map_get(&info->gen_procs, base_entity->identifier.load()); + if (found_gen_procs) { MUTEX_GUARD(&found_gen_procs->mutex); for (Entity *other : found_gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { + // @@GPM + mutex_unlock(&info->gen_procs_mutex); + if (poly_proc_data) { poly_proc_data->gen_entity = other; } @@ -465,6 +470,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E Ast *cloned_proc_type_node = clone_ast(pt->node); success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands); if (!success) { + // @@GPM + mutex_unlock(&info->gen_procs_mutex); return false; } @@ -473,6 +480,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E for (Entity *other : found_gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { + // @@GPM + mutex_unlock(&info->gen_procs_mutex); + if (poly_proc_data) { poly_proc_data->gen_entity = other; } @@ -498,6 +508,11 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } } + if (found_gen_procs) { + // @@GPM + mutex_unlock(&info->gen_procs_mutex); + } + Ast *proc_lit = clone_ast(old_decl->proc_lit); ast_node(pl, ProcLit, proc_lit); @@ -555,6 +570,19 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } } + if (found_gen_procs) { + MUTEX_GUARD(&found_gen_procs->mutex); + array_add(&found_gen_procs->procs, entity); + } else { + GenProcsData gen_proc_data = {}; + gen_proc_data.procs = array_make(heap_allocator()); + array_add(&gen_proc_data.procs, entity); + map_set(&info->gen_procs, base_entity->identifier.load(), gen_proc_data); + + // @@GPM + mutex_unlock(&info->gen_procs_mutex); + } + ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); proc_info->file = file; proc_info->token = token; @@ -565,15 +593,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E proc_info->generated_from_polymorphic = true; proc_info->poly_def_node = poly_def_node; - if (found_gen_procs) { - MUTEX_GUARD(&found_gen_procs->mutex); - array_add(&found_gen_procs->procs, entity); - } else { - GenProcsData gen_proc_data = {}; - gen_proc_data.procs = array_make(heap_allocator()); - array_add(&gen_proc_data.procs, entity); - map_set(&info->gen_procs, base_entity->identifier.load(), gen_proc_data); - } if (poly_proc_data) { poly_proc_data->gen_entity = entity; -- cgit v1.2.3 From 69b075782bac981ceeea5eea8f544e346f0fe6b5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 22:40:28 +0000 Subject: Use a package local mutex for `add_type_and_value` --- src/check_decl.cpp | 9 ++++++--- src/check_expr.cpp | 56 +++++++++++++++++++++++++++--------------------------- src/check_type.cpp | 2 +- src/checker.cpp | 13 +++++++++---- src/checker.hpp | 2 +- src/parser.hpp | 1 + 6 files changed, 46 insertions(+), 37 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 2b6868f05..e3486924c 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -45,7 +45,7 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o if (operand->mode == Addressing_Type) { if (e->type != nullptr && is_type_typeid(e->type)) { add_type_info_type(ctx, operand->type); - add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type)); + add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type)); return e->type; } else { gbString t = type_to_string(operand->type); @@ -1585,13 +1585,16 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de // NOTE(bill): Add the dependencies from the procedure literal (lambda) // But only at the procedure level - MUTEX_GUARD_BLOCK(decl->deps_mutex) MUTEX_GUARD_BLOCK(decl->parent->deps_mutex) { + MUTEX_GUARD_BLOCK(decl->deps_mutex) + MUTEX_GUARD_BLOCK(decl->parent->deps_mutex) { for (auto const &entry : decl->deps) { Entity *e = entry.ptr; ptr_set_add(&decl->parent->deps, e); } } - MUTEX_GUARD_BLOCK(decl->type_info_deps_mutex) MUTEX_GUARD_BLOCK(decl->parent->type_info_deps_mutex) { + + MUTEX_GUARD_BLOCK(decl->type_info_deps_mutex) + MUTEX_GUARD_BLOCK(decl->parent->type_info_deps_mutex) { for (auto const &entry : decl->type_info_deps) { Type *t = entry.ptr; ptr_set_add(&decl->parent->type_info_deps, t); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b40c48459..9feac93ea 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -852,7 +852,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand PolyProcData poly_proc_data = {}; if (check_polymorphic_procedure_assignment(c, operand, type, operand->expr, &poly_proc_data)) { Entity *e = poly_proc_data.gen_entity; - add_type_and_value(c->info, operand->expr, Addressing_Value, e->type, {}); + add_type_and_value(c, operand->expr, Addressing_Value, e->type, {}); add_entity_use(c, operand->expr, e); return 4; } @@ -1082,7 +1082,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ if (check_is_assignable_to(c, operand, type)) { if (operand->mode == Addressing_Type && is_type_typeid(type)) { add_type_info_type(c, operand->type); - add_type_and_value(c->info, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); + add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); } } else { gbString expr_str = expr_to_string(operand->expr); @@ -2374,7 +2374,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok if (x->mode == Addressing_Type && is_type_typeid(y->type)) { add_type_info_type(c, x->type); add_type_info_type(c, y->type); - add_type_and_value(c->info, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type)); + add_type_and_value(c, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type)); x->mode = Addressing_Value; x->type = t_untyped_bool; @@ -2382,7 +2382,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok } else if (is_type_typeid(x->type) && y->mode == Addressing_Type) { add_type_info_type(c, x->type); add_type_info_type(c, y->type); - add_type_and_value(c->info, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type)); + add_type_and_value(c, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type)); x->mode = Addressing_Value; x->type = t_untyped_bool; @@ -3615,7 +3615,7 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, if (old == nullptr) { if (type != nullptr && type != t_invalid) { if (e->tav.type == nullptr || e->tav.type == t_invalid) { - add_type_and_value(c->info, e, e->tav.mode, type ? type : e->tav.type, e->tav.value); + add_type_and_value(c, e, e->tav.mode, type ? type : e->tav.type, e->tav.value); if (e->kind == Ast_TernaryIfExpr) { update_untyped_expr_type(c, e->TernaryIfExpr.x, type, final); update_untyped_expr_type(c, e->TernaryIfExpr.y, type, final); @@ -3721,7 +3721,7 @@ gb_internal void update_untyped_expr_type(CheckerContext *c, Ast *e, Type *type, return; } - add_type_and_value(c->info, e, old->mode, type, old->value); + add_type_and_value(c, e, old->mode, type, old->value); } gb_internal void update_untyped_expr_value(CheckerContext *c, Ast *e, ExactValue value) { @@ -4569,7 +4569,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->mode = Addressing_ProcGroup; operand->proc_group = entity; - add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return entity; } GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind])); @@ -4738,7 +4738,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved); - add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return swizzle_entity; } end_of_array_selector_swizzle:; @@ -4782,7 +4782,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->value = field_value; operand->type = entity->type; add_entity_use(c, selector, entity); - add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return entity; } @@ -4807,7 +4807,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->value = field_value; operand->type = entity->type; add_entity_use(c, selector, entity); - add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return entity; } @@ -4895,7 +4895,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod break; } - add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return entity; } @@ -5361,7 +5361,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (o.mode == Addressing_Type && is_type_typeid(e->type)) { add_type_info_type(c, o.type); - add_type_and_value(c->info, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type)); + add_type_and_value(c, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type)); } else if (show_error && is_type_untyped(o.type)) { update_untyped_expr_type(c, o.expr, t, true); } @@ -5412,7 +5412,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } if (o.mode == Addressing_Type && is_type_typeid(t)) { add_type_info_type(c, o.type); - add_type_and_value(c->info, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); + add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); } else if (show_error && is_type_untyped(o.type)) { update_untyped_expr_type(c, o.expr, t, true); } @@ -5425,7 +5425,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; - add_type_and_value(c->info, ce->proc, Addressing_Value, final_proc_type, {}); + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); } return err; @@ -5625,7 +5625,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { if (o->mode == Addressing_Type && is_type_typeid(e->type)) { add_type_info_type(c, o->type); - add_type_and_value(c->info, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); } } @@ -5633,7 +5633,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { data->score = score; data->result_type = pt->results; data->gen_entity = gen_entity; - add_type_and_value(c->info, ce->proc, Addressing_Value, proc_type, {}); + add_type_and_value(c, ce->proc, Addressing_Value, proc_type, {}); } return err; @@ -6635,7 +6635,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c operand->builtin_id = BuiltinProc_DIRECTIVE; operand->expr = proc; operand->type = t_invalid; - add_type_and_value(c->info, proc, operand->mode, operand->type, operand->value); + add_type_and_value(c, proc, operand->mode, operand->type, operand->value); } else { error(proc, "Unknown directive: #%.*s", LIT(name)); operand->expr = proc; @@ -6713,7 +6713,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c 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, call, Addressing_Type, ot, empty_exact_value); } else { operand->mode = Addressing_Invalid; operand->type = t_invalid; @@ -6885,7 +6885,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - // add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + // add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return Expr_Expr; } @@ -7129,8 +7129,8 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand * return false; } - 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(c, ie->left, x->mode, x->type, x->value); + add_type_and_value(c, ie->right, y->mode, y->type, y->value); return true; } @@ -7146,7 +7146,7 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera return true; } if (expr->kind == Ast_ProcLit) { - add_type_and_value(c->info, expr, Addressing_Constant, type_of_expr(expr), exact_value_procedure(expr)); + add_type_and_value(c, expr, Addressing_Constant, type_of_expr(expr), exact_value_procedure(expr)); return true; } } @@ -7255,7 +7255,7 @@ gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type * Type *pt = base_type(type_of_expr(expr->CallExpr.proc)); if (is_type_proc(pt)) { Type *tuple = pt->Proc.results; - add_type_and_value(c->info, x->expr, x->mode, tuple, x->value); + add_type_and_value(c, x->expr, x->mode, tuple, x->value); if (pt->Proc.result_count >= 2) { if (ok_type_) *ok_type_ = tuple->Tuple.variables[1]->type; @@ -7268,7 +7268,7 @@ gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type * Type *tuple = make_optional_ok_type(x->type); if (ok_type_) *ok_type_ = tuple->Tuple.variables[1]->type; - add_type_and_value(c->info, x->expr, x->mode, tuple, x->value); + add_type_and_value(c, x->expr, x->mode, tuple, x->value); x->type = tuple; GB_ASSERT(is_type_tuple(type_of_expr(x->expr))); } @@ -7688,7 +7688,7 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node Type *left_type = nullptr; Type *right_type = nullptr; check_or_else_split_types(c, &x, name, &left_type, &right_type); - add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); + add_type_and_value(c, arg, x.mode, x.type, x.value); if (left_type != nullptr) { if (!y_is_diverging) { @@ -7723,7 +7723,7 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no Type *left_type = nullptr; Type *right_type = nullptr; check_or_return_split_types(c, &x, name, &left_type, &right_type); - add_type_and_value(&c->checker->info, re->expr, x.mode, x.type, x.value); + add_type_and_value(c, re->expr, x.mode, x.type, x.value); if (right_type == nullptr) { check_or_else_expr_no_value_error(c, name, x, type_hint); @@ -8149,7 +8149,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(elem, "Expected a constant integer as an array field"); continue; } - // add_type_and_value(c->info, op_index.expr, op_index.mode, op_index.type, op_index.value); + // add_type_and_value(c, op_index.expr, op_index.mode, op_index.type, op_index.value); i64 index = exact_value_to_i64(op_index.value); @@ -9783,7 +9783,7 @@ gb_internal ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, T } check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed"); - add_type_and_value(c->info, node, o->mode, o->type, o->value); + add_type_and_value(c, node, o->mode, o->type, o->value); return kind; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 4634e1fbe..05fdbf4d3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3045,7 +3045,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) #endif if (is_type_typed(type)) { - add_type_and_value(ctx->info, e, Addressing_Type, type, empty_exact_value); + add_type_and_value(ctx, 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 f80ea9e4c..e48142c82 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1440,7 +1440,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { if (expr == nullptr) { return; } @@ -1451,7 +1451,12 @@ gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mo return; } - mutex_lock(&i->type_and_value_mutex); + BlockingMutex *mutex = &ctx->info->type_and_value_mutex; + if (ctx->pkg) { + mutex = &ctx->pkg->type_and_value_mutex; + } + + mutex_lock(mutex); Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; @@ -1473,7 +1478,7 @@ gb_internal void add_type_and_value(CheckerInfo *i, Ast *expr, AddressingMode mo expr = unparen_expr(expr); } - mutex_unlock(&i->type_and_value_mutex); + mutex_unlock(mutex); } gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { @@ -5701,7 +5706,7 @@ gb_internal void check_parsed_files(Checker *c) { if (is_type_typed(u.info->type)) { compiler_error("%s (type %s) is typed!", expr_to_string(u.expr), type_to_string(u.info->type)); } - add_type_and_value(&c->info, u.expr, u.info->mode, u.info->type, u.info->value); + add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value); } diff --git a/src/checker.hpp b/src/checker.hpp index 62f655f95..04cb1e311 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -482,7 +482,7 @@ gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **s gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); diff --git a/src/parser.hpp b/src/parser.hpp index c33739ebe..b492cfa85 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -174,6 +174,7 @@ struct AstPackage { BlockingMutex files_mutex; BlockingMutex foreign_files_mutex; + BlockingMutex type_and_value_mutex; MPMCQueue exported_entity_queue; -- cgit v1.2.3 From 8ece92f1f69217ae5b143cf0e7d812c0f857fa8d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 23:21:16 +0000 Subject: Minimize the parapoly mutex usage a bit --- src/check_expr.cpp | 94 +++++++++++++++++++++-------------------------- src/checker.hpp | 2 +- src/llvm_backend_stmt.cpp | 5 ++- 3 files changed, 46 insertions(+), 55 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9feac93ea..65a411dc1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -434,20 +434,22 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return false; } - GenProcsData *found_gen_procs = nullptr; + GenProcsData *gen_procs = nullptr; - // @@GPM + // @@GPM ////////////////////////// mutex_lock(&info->gen_procs_mutex); + /////////////////////////////////// - found_gen_procs = map_get(&info->gen_procs, base_entity->identifier.load()); - - if (found_gen_procs) { - MUTEX_GUARD(&found_gen_procs->mutex); - for (Entity *other : found_gen_procs->procs) { + auto *found = map_get(&info->gen_procs, base_entity->identifier.load()); + if (found) { + gen_procs = *found; + MUTEX_GUARD(&gen_procs->mutex); + for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { - // @@GPM + // @@GPM //////////////////////////// mutex_unlock(&info->gen_procs_mutex); + ///////////////////////////////////// if (poly_proc_data) { poly_proc_data->gen_entity = other; @@ -455,6 +457,10 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } + } else { + gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); + gen_procs->procs.allocator = heap_allocator(); + map_set(&info->gen_procs, base_entity->identifier.load(), gen_procs); } { @@ -469,50 +475,43 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E // LEAK TODO(bill): Cloning this AST may be leaky Ast *cloned_proc_type_node = clone_ast(pt->node); success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands); + + // @@GPM //////////////////////////// + mutex_unlock(&info->gen_procs_mutex); + ///////////////////////////////////// + if (!success) { - // @@GPM - mutex_unlock(&info->gen_procs_mutex); return false; } - if (found_gen_procs) { - MUTEX_GUARD(&found_gen_procs->mutex); - for (Entity *other : found_gen_procs->procs) { - Type *pt = base_type(other->type); - if (are_types_identical(pt, final_proc_type)) { - // @@GPM - mutex_unlock(&info->gen_procs_mutex); - - if (poly_proc_data) { - poly_proc_data->gen_entity = other; - } + MUTEX_GUARD(&gen_procs->mutex); + for (Entity *other : gen_procs->procs) { + Type *pt = base_type(other->type); + if (are_types_identical(pt, final_proc_type)) { + if (poly_proc_data) { + poly_proc_data->gen_entity = other; + } - DeclInfo *decl = other->decl_info; - if (decl->proc_checked_state != ProcCheckedState_Checked) { - ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); - proc_info->file = other->file; - proc_info->token = other->token; - proc_info->decl = decl; - proc_info->type = other->type; - proc_info->body = decl->proc_lit->ProcLit.body; - proc_info->tags = other->Procedure.tags;; - proc_info->generated_from_polymorphic = true; - proc_info->poly_def_node = poly_def_node; - - check_procedure_later(nctx.checker, proc_info); - } + DeclInfo *decl = other->decl_info; + if (decl->proc_checked_state != ProcCheckedState_Checked) { + ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); + proc_info->file = other->file; + proc_info->token = other->token; + proc_info->decl = decl; + proc_info->type = other->type; + proc_info->body = decl->proc_lit->ProcLit.body; + proc_info->tags = other->Procedure.tags;; + proc_info->generated_from_polymorphic = true; + proc_info->poly_def_node = poly_def_node; - return true; + check_procedure_later(nctx.checker, proc_info); } + + return true; } } } - if (found_gen_procs) { - // @@GPM - mutex_unlock(&info->gen_procs_mutex); - } - Ast *proc_lit = clone_ast(old_decl->proc_lit); ast_node(pl, ProcLit, proc_lit); @@ -570,17 +569,8 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } } - if (found_gen_procs) { - MUTEX_GUARD(&found_gen_procs->mutex); - array_add(&found_gen_procs->procs, entity); - } else { - GenProcsData gen_proc_data = {}; - gen_proc_data.procs = array_make(heap_allocator()); - array_add(&gen_proc_data.procs, entity); - map_set(&info->gen_procs, base_entity->identifier.load(), gen_proc_data); - - // @@GPM - mutex_unlock(&info->gen_procs_mutex); + MUTEX_GUARD_BLOCK(&gen_procs->mutex) { + array_add(&gen_procs->procs, entity); } ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); diff --git a/src/checker.hpp b/src/checker.hpp index 04cb1e311..cc92fce28 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -369,7 +369,7 @@ struct CheckerInfo { RecursiveMutex gen_procs_mutex; RecursiveMutex gen_types_mutex; - PtrMap gen_procs; // Key: Ast * | Identifier -> Entity + PtrMap gen_procs; // Key: Ast * | Identifier -> Entity PtrMap > gen_types; BlockingMutex type_info_mutex; // NOT recursive diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 8742423a5..2703c511a 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -57,8 +57,9 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) if (pl->body != nullptr) { auto *found = map_get(&info->gen_procs, ident); if (found) { - MUTEX_GUARD(&found->mutex); - for (Entity *e : found->procs) { + GenProcsData *gpd = *found; + MUTEX_GUARD(&gpd->mutex); + for (Entity *e : gpd->procs) { if (!ptr_set_exists(min_dep_set, e)) { continue; } -- cgit v1.2.3 From e10fe91ebacdf6256608672a805de9d376e698fe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 23:50:48 +0000 Subject: Narrow global `gen_procs_mutex` further --- src/check_expr.cpp | 9 +++------ src/checker.cpp | 1 + src/thread_pool.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 65a411dc1..e3c55870c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -439,7 +439,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E // @@GPM ////////////////////////// mutex_lock(&info->gen_procs_mutex); /////////////////////////////////// - auto *found = map_get(&info->gen_procs, base_entity->identifier.load()); if (found) { gen_procs = *found; @@ -462,6 +461,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E gen_procs->procs.allocator = heap_allocator(); map_set(&info->gen_procs, base_entity->identifier.load(), gen_procs); } + // @@GPM //////////////////////////// + mutex_unlock(&info->gen_procs_mutex); + ///////////////////////////////////// { // LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice @@ -475,11 +477,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E // LEAK TODO(bill): Cloning this AST may be leaky Ast *cloned_proc_type_node = clone_ast(pt->node); success = check_procedure_type(&nctx, final_proc_type, cloned_proc_type_node, &operands); - - // @@GPM //////////////////////////// - mutex_unlock(&info->gen_procs_mutex); - ///////////////////////////////////// - if (!success) { return false; } diff --git a/src/checker.cpp b/src/checker.cpp index c2cd1163a..ccd0f3627 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -51,6 +51,7 @@ gb_internal bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *f gb_internal void scope_reset(Scope *scope) { if (scope == nullptr) return; + MUTEX_GUARD(&scope->mutex); scope->head_child.store(nullptr, std::memory_order_relaxed); string_map_clear(&scope->elements); ptr_set_clear(&scope->imported); diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index b89e00454..07ab3d323 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -167,7 +167,7 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) { idx = (idx + 1) % cast(usize)pool->threads.count; Thread *thread = &pool->threads.data[idx]; - WorkerTask task, another_task; + WorkerTask task; if (!thread_pool_queue_pop(thread, &task)) { continue; } -- cgit v1.2.3 From 670274ad8fc5ba52ea11c2d864d1915e107cc0e2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Jan 2023 23:56:37 +0000 Subject: More explicit uses of mutexes --- src/check_expr.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e3c55870c..3c998fc44 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -442,10 +442,11 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E auto *found = map_get(&info->gen_procs, base_entity->identifier.load()); if (found) { gen_procs = *found; - MUTEX_GUARD(&gen_procs->mutex); + mutex_lock(&gen_procs->mutex); // @local-mutex for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { + mutex_unlock(&gen_procs->mutex); // @local-mutex // @@GPM //////////////////////////// mutex_unlock(&info->gen_procs_mutex); ///////////////////////////////////// @@ -456,6 +457,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } + mutex_unlock(&gen_procs->mutex); // @local-mutex } else { gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); gen_procs->procs.allocator = heap_allocator(); @@ -481,10 +483,12 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return false; } - MUTEX_GUARD(&gen_procs->mutex); + mutex_lock(&gen_procs->mutex); // @local-mutex for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { + mutex_unlock(&gen_procs->mutex); // @local-mutex + if (poly_proc_data) { poly_proc_data->gen_entity = other; } @@ -507,6 +511,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } + mutex_unlock(&gen_procs->mutex); // @local-mutex } @@ -566,9 +571,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } } - MUTEX_GUARD_BLOCK(&gen_procs->mutex) { + mutex_lock(&gen_procs->mutex); // @local-mutex array_add(&gen_procs->procs, entity); - } + mutex_unlock(&gen_procs->mutex); // @local-mutex ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); proc_info->file = file; -- cgit v1.2.3 From 600f2b7284b8974a18827242c18e790dab0cf06a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 11:53:59 +0000 Subject: Use heap_allocator for all hash set types --- src/build_settings.cpp | 2 +- src/check_builtin.cpp | 2 +- src/check_decl.cpp | 2 +- src/check_expr.cpp | 1 - src/check_stmt.cpp | 1 - src/checker.cpp | 24 +++++++----------------- src/llvm_backend_general.cpp | 2 +- src/llvm_backend_type.cpp | 2 +- src/main.cpp | 8 ++++---- src/parser.cpp | 2 +- src/ptr_set.cpp | 21 +++++++++++++++------ src/string_set.cpp | 18 +++++++++++++----- 12 files changed, 45 insertions(+), 40 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 04d1ada93..75615a901 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1369,7 +1369,7 @@ gb_internal bool init_build_paths(String init_filename) { // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); - string_set_init(&bc->target_features_set, heap_allocator(), 1024); + string_set_init(&bc->target_features_set, 1024); // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 99d956f5e..36dc9b7a1 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3086,7 +3086,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } StringSet name_set = {}; - string_set_init(&name_set, heap_allocator(), 2*ce->args.count); + string_set_init(&name_set, 2*ce->args.count); for_array(i, ce->args) { String name = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index e3486924c..0c1a7c325 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1235,7 +1235,7 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, pg_entity->type = t_invalid; PtrSet entity_set = {}; - ptr_set_init(&entity_set, heap_allocator(), 2*pg->args.count); + ptr_set_init(&entity_set, 2*pg->args.count); for_array(i, pg->args) { Ast *arg = pg->args[i]; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3c998fc44..7a00b5353 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -196,7 +196,6 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b MUTEX_GUARD(objc_metadata->mutex); StringSet set = {}; - string_set_init(&set, heap_allocator()); defer (string_set_destroy(&set)); populate_check_did_you_mean_objc_entity(&set, e, is_type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index cf111e84c..945ba8f02 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1185,7 +1185,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ } PtrSet seen = {}; - ptr_set_init(&seen, heap_allocator()); defer (ptr_set_destroy(&seen)); for_array(i, bs->stmts) { diff --git a/src/checker.cpp b/src/checker.cpp index ccd0f3627..8da659461 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -72,7 +72,7 @@ gb_internal void entity_graph_node_set_destroy(EntityGraphNodeSet *s) { gb_internal void entity_graph_node_set_add(EntityGraphNodeSet *s, EntityGraphNode *n) { if (s->hashes.data == nullptr) { - ptr_set_init(s, heap_allocator()); + ptr_set_init(s); } ptr_set_add(s, n); } @@ -118,15 +118,10 @@ gb_internal void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j gb_internal void import_graph_node_set_destroy(ImportGraphNodeSet *s) { - if (s->hashes.data != nullptr) { - ptr_set_destroy(s); - } + ptr_set_destroy(s); } gb_internal void import_graph_node_set_add(ImportGraphNodeSet *s, ImportGraphNode *n) { - if (s->hashes.data == nullptr) { - ptr_set_init(s, heap_allocator()); - } ptr_set_add(s, n); } @@ -185,8 +180,8 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { gb_zero_item(d); d->parent = parent; d->scope = scope; - ptr_set_init(&d->deps, heap_allocator()); - ptr_set_init(&d->type_info_deps, heap_allocator()); + ptr_set_init(&d->deps); + ptr_set_init(&d->type_info_deps); array_init (&d->labels, heap_allocator()); } @@ -227,7 +222,7 @@ gb_internal Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_ele Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; string_map_init(&s->elements, heap_allocator(), init_elements_capacity); - ptr_set_init(&s->imported, heap_allocator(), 0); + ptr_set_init(&s->imported, 0); if (parent != nullptr && parent != builtin_pkg->scope) { Scope *prev_head_child = parent->head_child.exchange(s, std::memory_order_acq_rel); @@ -2270,8 +2265,8 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { isize entity_count = c->info.entities.count; isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor - ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap); - ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator()); + ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap); + ptr_set_init(&c->info.minimum_dependency_type_info_set); #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \ if (condition) { \ @@ -3388,7 +3383,6 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array const &at } StringSet set = {}; - string_set_init(&set, heap_allocator()); defer (string_set_destroy(&set)); for_array(i, attributes) { @@ -4759,7 +4753,6 @@ gb_internal void check_import_entities(Checker *c) { auto pq = priority_queue_create(dep_graph, import_graph_node_cmp, import_graph_node_swap); PtrSet emitted = {}; - ptr_set_init(&emitted, heap_allocator()); defer (ptr_set_destroy(&emitted)); Array package_order = {}; @@ -4773,7 +4766,6 @@ gb_internal void check_import_entities(Checker *c) { if (n->dep_count > 0) { PtrSet visited = {}; - ptr_set_init(&visited, heap_allocator()); defer (ptr_set_destroy(&visited)); auto path = find_import_path(c, pkg, pkg, &visited); @@ -4927,7 +4919,6 @@ gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet< bool made_visited = false; if (visited == nullptr) { made_visited = true; - ptr_set_init(&visited_, heap_allocator()); visited = &visited_; } defer (if (made_visited) { @@ -4990,7 +4981,6 @@ gb_internal void calculate_global_init_order(Checker *c) { auto pq = priority_queue_create(dep_graph, entity_graph_node_cmp, entity_graph_node_swap); PtrSet emitted = {}; - ptr_set_init(&emitted, heap_allocator()); defer (ptr_set_destroy(&emitted)); TIME_SECTION("calculate_global_init_order: queue sort"); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 22628e895..75675474a 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -133,7 +133,7 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { array_init(&gen->foreign_libraries, heap_allocator(), 0, 1024); - ptr_set_init(&gen->foreign_libraries_set, heap_allocator(), 1024); + ptr_set_init(&gen->foreign_libraries_set, 1024); if (USE_SEPARATE_MODULES) { for (auto const &entry : gen->info->packages) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 26bb614e6..c306cdead 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -2,7 +2,7 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ auto *set = &info->minimum_dependency_type_info_set; isize index = type_info_index(info, type, err_on_not_found); if (index >= 0) { - isize i = ptr_entry_index(set, index); + isize i = ptr_set_entry_index(set, index); if (i >= 0) { return i+1; } diff --git a/src/main.cpp b/src/main.cpp index ad9d6b0ef..91dcbdb01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,11 +212,11 @@ gb_internal i32 linker_stage(lbGenerator *gen) { StringSet libs = {}; - string_set_init(&libs, heap_allocator(), 64); + string_set_init(&libs, 64); defer (string_set_destroy(&libs)); StringSet asm_files = {}; - string_set_init(&asm_files, heap_allocator(), 64); + string_set_init(&asm_files, 64); defer (string_set_destroy(&asm_files)); for_array(j, gen->foreign_libraries) { @@ -371,7 +371,7 @@ gb_internal i32 linker_stage(lbGenerator *gen) { defer (gb_string_free(lib_str)); StringSet libs = {}; - string_set_init(&libs, heap_allocator(), 64); + string_set_init(&libs, 64); defer (string_set_destroy(&libs)); for_array(j, gen->foreign_libraries) { @@ -2518,7 +2518,7 @@ int main(int arg_count, char const **arg_ptr) { map_init(&build_context.defined_values, heap_allocator()); build_context.extra_packages.allocator = heap_allocator(); - string_set_init(&build_context.test_names, heap_allocator()); + string_set_init(&build_context.test_names); Array args = setup_args(arg_count, arg_ptr); diff --git a/src/parser.cpp b/src/parser.cpp index 4d2a8ecf4..046469c16 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4854,7 +4854,7 @@ gb_internal void destroy_ast_file(AstFile *f) { gb_internal bool init_parser(Parser *p) { GB_ASSERT(p != nullptr); - string_set_init(&p->imported_files, heap_allocator()); + string_set_init(&p->imported_files); array_init(&p->packages, heap_allocator()); return true; } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 9ecf1043e..affde5c2f 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -6,11 +6,11 @@ struct PtrSetEntry { template struct PtrSet { - Slice hashes; + Slice hashes; Array> entries; }; -template gb_internal void ptr_set_init (PtrSet *s, gbAllocator a, isize capacity = 16); +template gb_internal void ptr_set_init (PtrSet *s, isize capacity = 16); template gb_internal void ptr_set_destroy(PtrSet *s); template gb_internal T ptr_set_add (PtrSet *s, T ptr); template gb_internal bool ptr_set_update (PtrSet *s, T ptr); // returns true if it previously existed @@ -21,15 +21,18 @@ template gb_internal void ptr_set_grow (PtrSet *s); template gb_internal void ptr_set_rehash (PtrSet *s, isize new_count); template gb_internal void ptr_set_reserve(PtrSet *h, isize cap); +gb_internal gbAllocator ptr_set_allocator(void) { + return heap_allocator(); +} template -gb_internal void ptr_set_init(PtrSet *s, gbAllocator a, isize capacity) { +gb_internal void ptr_set_init(PtrSet *s, isize capacity) { if (capacity != 0) { capacity = next_pow2_isize(gb_max(16, capacity)); } - slice_init(&s->hashes, a, capacity); - array_init(&s->entries, a, 0, capacity); + slice_init(&s->hashes, ptr_set_allocator(), capacity); + array_init(&s->entries, ptr_set_allocator(), 0, capacity); for (isize i = 0; i < capacity; i++) { s->hashes.data[i] = MAP_SENTINEL; } @@ -37,6 +40,9 @@ gb_internal void ptr_set_init(PtrSet *s, gbAllocator a, isize capacity) { template gb_internal void ptr_set_destroy(PtrSet *s) { + if (s->entries.allocator.proc == nullptr) { + s->entries.allocator = ptr_set_allocator(); + } slice_free(&s->hashes, s->entries.allocator); array_free(&s->entries); } @@ -118,6 +124,9 @@ gb_internal void ptr_set_reset_entries(PtrSet *s) { template gb_internal void ptr_set_reserve(PtrSet *s, isize cap) { + if (s->entries.allocator.proc == nullptr) { + s->entries.allocator = ptr_set_allocator(); + } array_reserve(&s->entries, cap); if (s->entries.count*2 < s->hashes.count) { return; @@ -139,7 +148,7 @@ gb_internal gb_inline bool ptr_set_exists(PtrSet *s, T ptr) { } template -gb_internal gb_inline isize ptr_entry_index(PtrSet *s, T ptr) { +gb_internal gb_inline isize ptr_set_entry_index(PtrSet *s, T ptr) { isize index = ptr_set__find(s, ptr).entry_index; if (index != MAP_SENTINEL) { return index; diff --git a/src/string_set.cpp b/src/string_set.cpp index 1c97d253e..753afa9bf 100644 --- a/src/string_set.cpp +++ b/src/string_set.cpp @@ -10,7 +10,7 @@ struct StringSet { }; -gb_internal void string_set_init (StringSet *s, gbAllocator a, isize capacity = 16); +gb_internal void string_set_init (StringSet *s, isize capacity = 16); gb_internal void string_set_destroy(StringSet *s); gb_internal void string_set_add (StringSet *s, String const &str); gb_internal bool string_set_update (StringSet *s, String const &str); // returns true if it previously existed @@ -20,18 +20,24 @@ gb_internal void string_set_clear (StringSet *s); gb_internal void string_set_grow (StringSet *s); gb_internal void string_set_rehash (StringSet *s, isize new_count); +gb_internal gbAllocator string_set_allocator(void) { + return heap_allocator(); +} -gb_internal gb_inline void string_set_init(StringSet *s, gbAllocator a, isize capacity) { +gb_internal gb_inline void string_set_init(StringSet *s, isize capacity) { capacity = next_pow2_isize(gb_max(16, capacity)); - slice_init(&s->hashes, a, capacity); - array_init(&s->entries, a, 0, capacity); + slice_init(&s->hashes, string_set_allocator(), capacity); + array_init(&s->entries, string_set_allocator(), 0, capacity); for (isize i = 0; i < capacity; i++) { s->hashes.data[i] = MAP_SENTINEL; } } gb_internal gb_inline void string_set_destroy(StringSet *s) { + if (s->entries.allocator.proc == nullptr) { + s->entries.allocator = string_set_allocator(); + } slice_free(&s->hashes, s->entries.allocator); array_free(&s->entries); } @@ -106,6 +112,9 @@ gb_internal void string_set_reset_entries(StringSet *s) { } gb_internal void string_set_reserve(StringSet *s, isize cap) { + if (s->entries.allocator.proc == nullptr) { + s->entries.allocator = string_set_allocator(); + } array_reserve(&s->entries, cap); if (s->entries.count*2 < s->hashes.count) { return; @@ -217,7 +226,6 @@ gb_internal gb_inline void string_set_clear(StringSet *s) { } - gb_internal StringSetEntry *begin(StringSet &m) { return m.entries.data; } -- cgit v1.2.3 From 252be0fb417f9cdde5e9c4b348cd995a20433aea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 11:59:52 +0000 Subject: Make all maps use heap allocator implicitly --- src/check_builtin.cpp | 2 +- src/check_expr.cpp | 3 +-- src/check_stmt.cpp | 1 - src/checker.cpp | 33 +++++++++++++++------------------ src/common.cpp | 2 +- src/docs_writer.cpp | 11 +++++------ src/llvm_backend_general.cpp | 44 ++++++++++++++++++++++---------------------- src/llvm_backend_proc.cpp | 10 +++++----- src/main.cpp | 2 +- src/ptr_map.cpp | 18 ++++++++++++++---- src/string_map.cpp | 18 ++++++++++++++---- 11 files changed, 79 insertions(+), 65 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 36dc9b7a1..af196234e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1110,7 +1110,7 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String new_cache->path = path; new_cache->data = data; new_cache->file_error = file_error; - string_map_init(&new_cache->hashes, heap_allocator(), 32); + string_map_init(&new_cache->hashes, 32); string_map_set(&c->info->load_file_cache, path, new_cache); if (cache_) *cache_ = new_cache; } else { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7a00b5353..030bfb8e6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5753,7 +5753,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op // in order to improve the type inference system StringMap type_hint_map = {}; // Key: String - string_map_init(&type_hint_map, heap_allocator(), 2*args.count); + string_map_init(&type_hint_map, 2*args.count); defer (string_map_destroy(&type_hint_map)); Type *ptype = nullptr; @@ -8283,7 +8283,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * bool is_partial = cl->tag && (cl->tag->BasicDirective.name.string == "partial"); SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue - map_init(&seen, heap_allocator()); defer (map_destroy(&seen)); if (cl->elems.count > 0 && cl->elems[0]->kind == Ast_FieldValue) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 945ba8f02..7192b16b5 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -929,7 +929,6 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags } SeenMap seen = {}; // NOTE(bill): Multimap, Key: ExactValue - map_init(&seen, heap_allocator()); defer (map_destroy(&seen)); for_array(stmt_index, bs->stmts) { diff --git a/src/checker.cpp b/src/checker.cpp index 8da659461..8779d9d45 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -221,7 +221,7 @@ gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { gb_internal Scope *create_scope(CheckerInfo *info, Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; - string_map_init(&s->elements, heap_allocator(), init_elements_capacity); + string_map_init(&s->elements, init_elements_capacity); ptr_set_init(&s->imported, 0); if (parent != nullptr && parent != builtin_pkg->scope) { @@ -1135,14 +1135,14 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->definitions, a); array_init(&i->entities, a); - map_init(&i->global_untyped, a); - string_map_init(&i->foreigns, a); - map_init(&i->gen_procs, a); - map_init(&i->gen_types, a); + map_init(&i->global_untyped); + string_map_init(&i->foreigns); + map_init(&i->gen_procs); + map_init(&i->gen_types); array_init(&i->type_info_types, a); - map_init(&i->type_info_map, a); - string_map_init(&i->files, a); - string_map_init(&i->packages, a); + map_init(&i->type_info_map); + string_map_init(&i->files); + string_map_init(&i->packages); array_init(&i->variable_init_order, a); array_init(&i->testing_procedures, a, 0, 0); array_init(&i->init_procedures, a, 0, 0); @@ -1160,8 +1160,8 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpmc_init(&i->intrinsics_entry_point_usage, a, 1<<10); // just waste some memory here, even if it probably never used - map_init(&i->objc_msgSend_types, a); - string_map_init(&i->load_file_cache, a); + map_init(&i->objc_msgSend_types); + string_map_init(&i->load_file_cache); array_init(&i->all_procedures, heap_allocator()); @@ -2490,7 +2490,7 @@ gb_internal bool is_entity_a_dependency(Entity *e) { gb_internal Array generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) { PtrMap M = {}; - map_init(&M, allocator, info->entities.count); + map_init(&M, info->entities.count); defer (map_destroy(&M)); for_array(i, info->entities) { Entity *e = info->entities[i]; @@ -4200,7 +4200,7 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap generate_import_dependency_graph(Checker *c) { PtrMap M = {}; - map_init(&M, heap_allocator(), 2*c->parser->packages.count); + map_init(&M, 2*c->parser->packages.count); defer (map_destroy(&M)); for_array(i, c->parser->packages) { @@ -4688,7 +4688,7 @@ gb_internal void check_collect_entities_all(Checker *c) { auto *wd = &collect_entity_worker_data[i]; wd->c = c; wd->ctx = make_checker_context(c); - map_init(&wd->untyped, heap_allocator()); + map_init(&wd->untyped); } for (auto const &entry : c->info.files.entries) { @@ -4804,7 +4804,6 @@ gb_internal void check_import_entities(Checker *c) { CheckerContext ctx = make_checker_context(c); UntypedExprInfoMap untyped = {}; - map_init(&untyped, heap_allocator()); defer (map_destroy(&untyped)); isize min_pkg_index = 0; @@ -5159,7 +5158,6 @@ gb_internal void check_unchecked_bodies(Checker *c) { GB_ASSERT(c->procs_to_check.count == 0); UntypedExprInfoMap untyped = {}; - map_init(&untyped, heap_allocator()); defer (map_destroy(&untyped)); // use the `procs_to_check` array @@ -5212,7 +5210,6 @@ gb_internal void check_unchecked_bodies(Checker *c) { gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) { GB_ASSERT(DEBUG_CHECK_ALL_PROCEDURES); UntypedExprInfoMap untyped = {}; - map_init(&untyped, heap_allocator()); defer (map_destroy(&untyped)); @@ -5345,7 +5342,7 @@ gb_internal void check_procedure_bodies(Checker *c) { for (isize i = 0; i < thread_count; i++) { check_procedure_bodies_worker_data[i].c = c; - map_init(&check_procedure_bodies_worker_data[i].untyped, heap_allocator()); + map_init(&check_procedure_bodies_worker_data[i].untyped); } defer (for (isize i = 0; i < thread_count; i++) { @@ -5545,7 +5542,7 @@ gb_internal void check_deferred_procedures(Checker *c) { gb_internal void check_unique_package_names(Checker *c) { StringMap pkgs = {}; // Key: package name - string_map_init(&pkgs, heap_allocator(), 2*c->info.packages.entries.count); + string_map_init(&pkgs, 2*c->info.packages.entries.count); defer (string_map_destroy(&pkgs)); for (auto const &entry : c->info.packages) { diff --git a/src/common.cpp b/src/common.cpp index 3b6ea59e8..199a263a1 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -373,7 +373,7 @@ gb_internal char const *string_intern(String const &string) { } gb_internal void init_string_interner(void) { - map_init(&string_intern_map, heap_allocator()); + map_init(&string_intern_map); } diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index bab97158d..2aefe29eb 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -53,13 +53,12 @@ gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker * gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) { w->state = OdinDocWriterState_Preparing; - gbAllocator a = heap_allocator(); - string_map_init(&w->string_cache, a); + string_map_init(&w->string_cache); - map_init(&w->file_cache, a); - map_init(&w->pkg_cache, a); - map_init(&w->entity_cache, a); - map_init(&w->type_cache, a); + map_init(&w->file_cache); + map_init(&w->pkg_cache); + map_init(&w->entity_cache); + map_init(&w->type_cache); odin_doc_writer_item_tracker_init(&w->files, 1); odin_doc_writer_item_tracker_init(&w->pkgs, 1); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 75675474a..a849929f0 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -55,30 +55,30 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { } gbAllocator a = heap_allocator(); - map_init(&m->types, a); - map_init(&m->func_raw_types, a); - map_init(&m->struct_field_remapping, a); - map_init(&m->values, a); - map_init(&m->soa_values, a); - string_map_init(&m->members, a); - map_init(&m->procedure_values, a); - string_map_init(&m->procedures, a); - string_map_init(&m->const_strings, a); - map_init(&m->function_type_map, a); - map_init(&m->equal_procs, a); - map_init(&m->hasher_procs, a); - map_init(&m->map_get_procs, a); - map_init(&m->map_set_procs, a); + map_init(&m->types); + map_init(&m->func_raw_types); + map_init(&m->struct_field_remapping); + map_init(&m->values); + map_init(&m->soa_values); + string_map_init(&m->members); + map_init(&m->procedure_values); + string_map_init(&m->procedures); + string_map_init(&m->const_strings); + map_init(&m->function_type_map); + map_init(&m->equal_procs); + map_init(&m->hasher_procs); + map_init(&m->map_get_procs); + map_init(&m->map_set_procs); array_init(&m->procedures_to_generate, a, 0, 1024); array_init(&m->missing_procedures_to_check, a, 0, 16); - map_init(&m->debug_values, a); + map_init(&m->debug_values); array_init(&m->debug_incomplete_types, a, 0, 1024); - string_map_init(&m->objc_classes, a); - string_map_init(&m->objc_selectors, a); + string_map_init(&m->objc_classes); + string_map_init(&m->objc_selectors); - map_init(&m->map_info_map, a, 0); - map_init(&m->map_cell_info_map, a, 0); + map_init(&m->map_info_map, 0); + map_init(&m->map_cell_info_map, 0); } @@ -127,9 +127,9 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { gen->info = &c->info; - map_init(&gen->modules, permanent_allocator(), gen->info->packages.entries.count*2); - map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2); - map_init(&gen->anonymous_proc_lits, heap_allocator(), 1024); + map_init(&gen->modules, gen->info->packages.entries.count*2); + map_init(&gen->modules_through_ctx, gen->info->packages.entries.count*2); + map_init(&gen->anonymous_proc_lits, 1024); array_init(&gen->foreign_libraries, heap_allocator(), 0, 1024); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7245bdd80..c66462bc1 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -119,9 +119,9 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i p->branch_blocks.allocator = a; p->context_stack.allocator = a; p->scope_stack.allocator = a; - map_init(&p->selector_values, a, 0); - map_init(&p->selector_addr, a, 0); - map_init(&p->tuple_fix_map, a, 0); + map_init(&p->selector_values, 0); + map_init(&p->selector_addr, 0); + map_init(&p->tuple_fix_map, 0); if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); @@ -345,7 +345,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name p->blocks.allocator = a; p->branch_blocks.allocator = a; p->context_stack.allocator = a; - map_init(&p->tuple_fix_map, a, 0); + map_init(&p->tuple_fix_map, 0); char *c_link_name = alloc_cstring(permanent_allocator(), p->name); @@ -486,7 +486,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { p->entry_block = lb_create_block(p, "entry", true); lb_start_block(p, p->entry_block); - map_init(&p->direct_parameters, heap_allocator()); + map_init(&p->direct_parameters); GB_ASSERT(p->type != nullptr); diff --git a/src/main.cpp b/src/main.cpp index 91dcbdb01..7ac78241e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2516,7 +2516,7 @@ int main(int arg_count, char const **arg_ptr) { add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core"))); add_library_collection(str_lit("vendor"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("vendor"))); - map_init(&build_context.defined_values, heap_allocator()); + map_init(&build_context.defined_values); build_context.extra_packages.allocator = heap_allocator(); string_set_init(&build_context.test_names); diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index 434680e91..083cd6697 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -46,7 +46,7 @@ gb_internal gb_inline u32 ptr_map_hash_key(void const *key) { } -template gb_internal void map_init (PtrMap *h, gbAllocator a, isize capacity = 16); +template gb_internal void map_init (PtrMap *h, isize capacity = 16); template gb_internal void map_destroy (PtrMap *h); template gb_internal V * map_get (PtrMap *h, K key); template gb_internal void map_set (PtrMap *h, K key, V const &value); @@ -68,11 +68,15 @@ template gb_internal void multi_map_remove (PtrMap< template gb_internal void multi_map_remove_all(PtrMap *h, K key); #endif +gb_internal gbAllocator map_allocator(void) { + return heap_allocator(); +} + template -gb_internal gb_inline void map_init(PtrMap *h, gbAllocator a, isize capacity) { +gb_internal gb_inline void map_init(PtrMap *h, isize capacity) { capacity = next_pow2_isize(capacity); - slice_init(&h->hashes, a, capacity); - array_init(&h->entries, a, 0, capacity); + slice_init(&h->hashes, map_allocator(), capacity); + array_init(&h->entries, map_allocator(), 0, capacity); for (isize i = 0; i < capacity; i++) { h->hashes.data[i] = MAP_SENTINEL; } @@ -80,6 +84,9 @@ gb_internal gb_inline void map_init(PtrMap *h, gbAllocator a, isize capaci template gb_internal gb_inline void map_destroy(PtrMap *h) { + if (h->entries.allocator.proc == nullptr) { + h->entries.allocator = map_allocator(); + } slice_free(&h->hashes, h->entries.allocator); array_free(&h->entries); } @@ -162,6 +169,9 @@ gb_internal void map_reset_entries(PtrMap *h) { template gb_internal void map_reserve(PtrMap *h, isize cap) { + if (h->entries.allocator.proc == nullptr) { + h->entries.allocator = map_allocator(); + } array_reserve(&h->entries, cap); if (h->entries.count*2 < h->hashes.count) { return; diff --git a/src/string_map.cpp b/src/string_map.cpp index 9f9374ece..b5db63e90 100644 --- a/src/string_map.cpp +++ b/src/string_map.cpp @@ -35,7 +35,7 @@ struct StringMap { }; -template gb_internal void string_map_init (StringMap *h, gbAllocator a, isize capacity = 16); +template gb_internal void string_map_init (StringMap *h, isize capacity = 16); template gb_internal void string_map_destroy (StringMap *h); template gb_internal T * string_map_get (StringMap *h, char const *key); @@ -56,11 +56,15 @@ template gb_internal void string_map_grow (StringMap template gb_internal void string_map_rehash (StringMap *h, isize new_count); template gb_internal void string_map_reserve (StringMap *h, isize cap); +gb_internal gbAllocator string_map_allocator(void) { + return heap_allocator(); +} + template -gb_internal gb_inline void string_map_init(StringMap *h, gbAllocator a, isize capacity) { +gb_internal gb_inline void string_map_init(StringMap *h, isize capacity) { capacity = next_pow2_isize(capacity); - slice_init(&h->hashes, a, capacity); - array_init(&h->entries, a, 0, capacity); + slice_init(&h->hashes, string_map_allocator(), capacity); + array_init(&h->entries, string_map_allocator(), 0, capacity); for (isize i = 0; i < capacity; i++) { h->hashes.data[i] = MAP_SENTINEL; } @@ -68,6 +72,9 @@ gb_internal gb_inline void string_map_init(StringMap *h, gbAllocator a, isize template gb_internal gb_inline void string_map_destroy(StringMap *h) { + if (h->entries.allocator.proc == nullptr) { + h->entries.allocator = string_map_allocator(); + } slice_free(&h->hashes, h->entries.allocator); array_free(&h->entries); } @@ -147,6 +154,9 @@ gb_internal void string_map_reset_entries(StringMap *h) { template gb_internal void string_map_reserve(StringMap *h, isize cap) { + if (h->entries.allocator.proc == nullptr) { + h->entries.allocator = string_map_allocator(); + } array_reserve(&h->entries, cap); if (h->entries.count*2 < h->hashes.count) { return; -- cgit v1.2.3 From 747a11a954824da7960a247299986f56d1316773 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 12:18:35 +0000 Subject: Allow all set entry types to be implicitly cast to their key/value type to allow for easier iteration --- src/build_settings.cpp | 6 ++---- src/check_decl.cpp | 6 ++---- src/check_expr.cpp | 7 +++---- src/checker.cpp | 38 +++++++++++++------------------------- src/ptr_set.cpp | 12 ++++++++---- src/string_map.cpp | 13 ++++++++++--- src/string_set.cpp | 15 +++++++++++---- src/types.cpp | 3 +-- 8 files changed, 50 insertions(+), 50 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 75615a901..1dff5f43e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1332,11 +1332,10 @@ gb_internal void enable_target_feature(TokenPos pos, String const &target_featur gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) { isize len = 0; isize i = 0; - for (auto const &entry : build_context.target_features_set) { + for (String const &feature : build_context.target_features_set) { if (i != 0) { len += 1; } - String feature = entry.value; len += feature.len; if (with_quotes) len += 2; i += 1; @@ -1344,13 +1343,12 @@ gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bo char *features = gb_alloc_array(allocator, char, len+1); len = 0; i = 0; - for (auto const &entry : build_context.target_features_set) { + for (String const &feature : build_context.target_features_set) { if (i != 0) { features[len++] = ','; } if (with_quotes) features[len++] = '"'; - String feature = entry.value; gb_memmove(features + len, feature.text, feature.len); len += feature.len; if (with_quotes) features[len++] = '"'; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 0c1a7c325..7b229db08 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1587,16 +1587,14 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de MUTEX_GUARD_BLOCK(decl->deps_mutex) MUTEX_GUARD_BLOCK(decl->parent->deps_mutex) { - for (auto const &entry : decl->deps) { - Entity *e = entry.ptr; + for (Entity *e : decl->deps) { ptr_set_add(&decl->parent->deps, e); } } MUTEX_GUARD_BLOCK(decl->type_info_deps_mutex) MUTEX_GUARD_BLOCK(decl->parent->type_info_deps_mutex) { - for (auto const &entry : decl->type_info_deps) { - Type *t = entry.ptr; + for (Type *t : decl->type_info_deps) { ptr_set_add(&decl->parent->type_info_deps, t); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 030bfb8e6..2924f9d13 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -202,8 +202,8 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name); defer (did_you_mean_destroy(&d)); - for (auto const &entry : set) { - did_you_mean_append(&d, entry.value); + for (String const &target : set) { + did_you_mean_append(&d, target); } check_did_you_mean_print(&d, prefix); } @@ -4942,8 +4942,7 @@ gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lh if (e != nullptr) { DeclInfo *decl = decl_info_of_entity(e); if (decl != nullptr) { - for (auto const &entry : decl->deps) { - Entity *dep = entry.ptr; + for (Entity *dep : decl->deps) { ptr_set_add(&c->decl->deps, dep); } } diff --git a/src/checker.cpp b/src/checker.cpp index 8779d9d45..0075fa543 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2222,12 +2222,11 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { return; } - for (auto const &entry : decl->type_info_deps) { - add_min_dep_type_info(c, entry.ptr); + for (Type *t : decl->type_info_deps) { + add_min_dep_type_info(c, t); } - for (auto const &entry : decl->deps) { - Entity *e = entry.ptr; + for (Entity *e : decl->deps) { add_dependency_to_set(c, e); if (e->kind == Entity_Procedure && e->Procedure.is_foreign) { Entity *fl = e->Procedure.foreign_library; @@ -2510,8 +2509,7 @@ gb_internal Array generate_entity_dependency_graph(CheckerInf DeclInfo *decl = decl_info_of_entity(e); GB_ASSERT(decl != nullptr); - for (auto const &entry : decl->deps) { - Entity *dep = entry.ptr; + for (Entity *dep : decl->deps) { if (dep->flags & EntityFlag_Field) { continue; } @@ -2537,15 +2535,12 @@ gb_internal Array generate_entity_dependency_graph(CheckerInf if (e->kind == Entity_Procedure) { // Connect each pred 'p' of 'n' with each succ 's' and from // the procedure node - for (auto const &p_entry : n->pred) { - EntityGraphNode *p = p_entry.ptr; - + for (EntityGraphNode *p : n->pred) { // Ignore self-cycles if (p != n) { // Each succ 's' of 'n' becomes a succ of 'p', and // each pred 'p' of 'n' becomes a pred of 's' - for (auto const &s_entry : n->succ) { - EntityGraphNode *s = s_entry.ptr; + for (EntityGraphNode *s : n->succ) { // Ignore self-cycles if (s != n) { if (p->entity->kind == Entity_Procedure && @@ -4784,8 +4779,7 @@ gb_internal void check_import_entities(Checker *c) { } } - for (auto const &entry : n->pred) { - ImportGraphNode *p = entry.ptr; + for (ImportGraphNode *p : n->pred) { p->dep_count = gb_max(p->dep_count-1, 0); priority_queue_fix(&pq, p->index); } @@ -4893,8 +4887,7 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSetdeps) { - Entity *dep = entry.ptr; + for (Entity *dep : var_decl->deps) { if (dep == end) { auto path = array_make(heap_allocator()); array_add(&path, dep); @@ -4944,8 +4937,7 @@ gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet< return path; } } else { - for (auto const &entry : decl->deps) { - Entity *dep = entry.ptr; + for (Entity *dep : decl->deps) { if (dep == end) { auto path = array_make(heap_allocator()); array_add(&path, dep); @@ -5002,8 +4994,7 @@ gb_internal void calculate_global_init_order(Checker *c) { } } - for (auto const &entry : n->pred) { - EntityGraphNode *p = entry.ptr; + for (EntityGraphNode *p : n->pred) { p->dep_count -= 1; p->dep_count = gb_max(p->dep_count, 0); priority_queue_fix(&pq, p->index); @@ -5163,8 +5154,7 @@ gb_internal void check_unchecked_bodies(Checker *c) { // use the `procs_to_check` array global_procedure_body_in_worker_queue = false; - for (auto const &entry : c->info.minimum_dependency_set) { - Entity *e = entry.ptr; + for (Entity *e : c->info.minimum_dependency_set) { if (e == nullptr || e->kind != Entity_Procedure) { continue; } @@ -5239,8 +5229,7 @@ gb_internal void check_test_procedures(Checker *c) { AstPackage *pkg = c->info.init_package; Scope *s = pkg->scope; - for (auto const &entry : build_context.test_names) { - String name = entry.value; + for (String const &name : build_context.test_names) { Entity *e = scope_lookup(s, name); if (e == nullptr) { Token tok = {}; @@ -5744,8 +5733,7 @@ gb_internal void check_parsed_files(Checker *c) { DeclInfo *decl = e->decl_info; ast_node(pl, ProcLit, decl->proc_lit); if (pl->inlining == ProcInlining_inline) { - for (auto const &entry : decl->deps) { - Entity *dep = entry.ptr; + for (Entity *dep : decl->deps) { if (dep == e) { error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string)); break; diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index affde5c2f..303bde07e 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -2,6 +2,10 @@ template struct PtrSetEntry { T ptr; MapIndex next; + + operator T() const noexcept { + return this->ptr; + } }; template @@ -245,21 +249,21 @@ gb_internal gb_inline void ptr_set_clear(PtrSet *s) { template -gb_internal PtrSetEntry *begin(PtrSet &m) { +gb_internal PtrSetEntry *begin(PtrSet &m) noexcept { return m.entries.data; } template -gb_internal PtrSetEntry const *begin(PtrSet const &m) { +gb_internal PtrSetEntry const *begin(PtrSet const &m) noexcept { return m.entries.data; } template -gb_internal PtrSetEntry *end(PtrSet &m) { +gb_internal PtrSetEntry *end(PtrSet &m) noexcept { return m.entries.data + m.entries.count; } template -gb_internal PtrSetEntry const *end(PtrSet const &m) { +gb_internal PtrSetEntry const *end(PtrSet const &m) noexcept { return m.entries.data + m.entries.count; } \ No newline at end of file diff --git a/src/string_map.cpp b/src/string_map.cpp index b5db63e90..74a16de73 100644 --- a/src/string_map.cpp +++ b/src/string_map.cpp @@ -1,6 +1,13 @@ struct StringHashKey { u32 hash; String string; + + operator String() const noexcept { + return this->string; + } + operator String const &() const noexcept { + return this->string; + } }; gb_internal gb_inline StringHashKey string_hash_string(String const &s) { @@ -283,11 +290,11 @@ gb_internal gb_inline void string_map_clear(StringMap *h) { template -gb_internal StringMapEntry *begin(StringMap &m) { +gb_internal StringMapEntry *begin(StringMap &m) noexcept { return m.entries.data; } template -gb_internal StringMapEntry const *begin(StringMap const &m) { +gb_internal StringMapEntry const *begin(StringMap const &m) noexcept { return m.entries.data; } @@ -298,6 +305,6 @@ gb_internal StringMapEntry *end(StringMap &m) { } template -gb_internal StringMapEntry const *end(StringMap const &m) { +gb_internal StringMapEntry const *end(StringMap const &m) noexcept { return m.entries.data + m.entries.count; } \ No newline at end of file diff --git a/src/string_set.cpp b/src/string_set.cpp index 753afa9bf..fb4640c20 100644 --- a/src/string_set.cpp +++ b/src/string_set.cpp @@ -2,6 +2,13 @@ struct StringSetEntry { u32 hash; MapIndex next; String value; + + operator String const() const noexcept { + return this->value; + } + operator String const &() const noexcept { + return this->value; + } }; struct StringSet { @@ -226,18 +233,18 @@ gb_internal gb_inline void string_set_clear(StringSet *s) { } -gb_internal StringSetEntry *begin(StringSet &m) { +gb_internal StringSetEntry *begin(StringSet &m) noexcept { return m.entries.data; } -gb_internal StringSetEntry const *begin(StringSet const &m) { +gb_internal StringSetEntry const *begin(StringSet const &m) noexcept { return m.entries.data; } -gb_internal StringSetEntry *end(StringSet &m) { +gb_internal StringSetEntry *end(StringSet &m) noexcept { return m.entries.data + m.entries.count; } -gb_internal StringSetEntry const *end(StringSet const &m) { +gb_internal StringSetEntry const *end(StringSet const &m) noexcept { return m.entries.data + m.entries.count; } \ No newline at end of file diff --git a/src/types.cpp b/src/types.cpp index 1e2d85ac6..d33c36e94 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -823,8 +823,7 @@ gb_internal bool type_ptr_set_exists(PtrSet *s, Type *t) { // TODO(bill, 2019-10-05): This is very slow and it's probably a lot // faster to cache types correctly - for (auto const &entry : *s) { - Type *f = entry.ptr; + for (Type *f : *s) { if (are_types_identical(t, f)) { ptr_set_add(s, t); return true; -- cgit v1.2.3 From 7380b7e61be55e4c2371f62401d6175c51ea0c6f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 12:37:41 +0000 Subject: Add more uses of C++ style `for` loops over `for_array` macro --- src/check_expr.cpp | 149 ++++++++++++++++++++--------------------------------- 1 file changed, 57 insertions(+), 92 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2924f9d13..c1787e7b6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -146,8 +146,8 @@ gb_internal void check_did_you_mean_print(DidYouMeanAnswers *d, char const *pref auto results = did_you_mean_results(d); if (results.count != 0) { error_line("\tSuggestion: Did you mean?\n"); - for_array(i, results) { - String const &target = results[i].target; + for (auto const &result : results) { + String const &target = result.target; error_line("\t\t%s%.*s\n", prefix, LIT(target)); // error_line("\t\t%.*s %td\n", LIT(target), results[i].distance); } @@ -166,19 +166,16 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity GB_ASSERT(t->kind == Type_Struct); if (is_type) { - for_array(i, objc_metadata->type_entries) { - String name = objc_metadata->type_entries[i].name; - string_set_add(set, name); + for (auto const &entry : objc_metadata->type_entries) { + string_set_add(set, entry.name); } } else { - for_array(i, objc_metadata->value_entries) { - String name = objc_metadata->value_entries[i].name; - string_set_add(set, name); + for (auto const &entry : objc_metadata->value_entries) { + string_set_add(set, entry.name); } } - for_array(i, t->Struct.fields) { - Entity *f = t->Struct.fields[i]; + for (Entity *f : t->Struct.fields) { if (f->flags & EntityFlag_Using && f->type != nullptr) { if (f->type->kind == Type_Named && f->type->Named.type_name) { populate_check_did_you_mean_objc_entity(set, f->type->Named.type_name, is_type); @@ -214,8 +211,8 @@ gb_internal void check_did_you_mean_type(String const &name, Array con DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); defer (did_you_mean_destroy(&d)); - for_array(i, fields) { - did_you_mean_append(&d, fields[i]->token.string); + for (Entity *e : fields) { + did_you_mean_append(&d, e->token.string); } check_did_you_mean_print(&d, prefix); } @@ -227,8 +224,8 @@ gb_internal void check_did_you_mean_type(String const &name, Slice con DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); defer (did_you_mean_destroy(&d)); - for_array(i, fields) { - did_you_mean_append(&d, fields[i]->token.string); + for (Entity *e : fields) { + did_you_mean_append(&d, e->token.string); } check_did_you_mean_print(&d, prefix); } @@ -781,8 +778,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } if (is_type_union(dst)) { - for_array(i, dst->Union.variants) { - Type *vt = dst->Union.variants[i]; + for (Type *vt : dst->Union.variants) { if (are_types_identical(vt, s)) { return 1; } @@ -798,8 +794,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } else if (is_type_untyped(src)) { i64 prev_lowest_score = -1; i64 lowest_score = -1; - for_array(i, dst->Union.variants) { - Type *vt = dst->Union.variants[i]; + for (Type *vt : dst->Union.variants) { i64 score = check_distance_between_types(c, operand, vt); if (score >= 0) { if (lowest_score < 0) { @@ -1031,8 +1026,8 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ if (type != nullptr && is_type_proc(type)) { Array procs = proc_group_entities(c, *operand); // NOTE(bill): These should be done - for_array(i, procs) { - Type *t = base_type(procs[i]->type); + for (Entity *e : procs) { + Type *t = base_type(e->type); if (t == t_invalid) { continue; } @@ -1040,7 +1035,6 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ x.mode = Addressing_Value; x.type = t; if (check_is_assignable_to(c, &x, type)) { - Entity *e = procs[i]; add_entity_use(c, operand->expr, e); good = true; break; @@ -1470,7 +1464,7 @@ gb_internal bool check_cycle(CheckerContext *c, Entity *curr, bool report) { return false; } for_array(i, *c->type_path) { - Entity *prev = (*c->type_path)[i]; + Entity *prev = c->type_path->data[i]; if (prev == curr) { if (report) { error(curr->token, "Illegal declaration cycle of `%.*s`", LIT(curr->token.string)); @@ -1535,8 +1529,8 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam if (type_hint != nullptr && is_type_proc(type_hint)) { // NOTE(bill): These should be done - for_array(i, procs) { - Type *t = base_type(procs[i]->type); + for (Entity *proc : procs) { + Type *t = base_type(proc->type); if (t == t_invalid) { continue; } @@ -1544,7 +1538,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam x.mode = Addressing_Value; x.type = t; if (check_is_assignable_to(c, &x, type_hint)) { - e = procs[i]; + e = proc; add_entity_use(c, n, e); skip = true; break; @@ -4174,8 +4168,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v if (cl->elems[0]->kind == Ast_FieldValue) { if (is_type_struct(node->tav.type)) { bool found = false; - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { continue; } @@ -4194,8 +4187,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v value = {}; } } else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) { - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { continue; } @@ -4578,8 +4570,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (entity->kind == Entity_ProcGroup) { Array procs = entity->ProcGroup.entities; bool skip = false; - for_array(i, procs) { - Entity *p = procs[i]; + for (Entity *p : procs) { Type *t = base_type(p->type); if (t == t_invalid) { continue; @@ -4958,7 +4949,7 @@ gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lh gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { bool optional_ok = false; isize tuple_index = 0; - for_array(i, rhs) { + for (Ast *rhs_expr : rhs) { CheckerContext c_ = *ctx; CheckerContext *c = &c_; @@ -4970,7 +4961,7 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array type_hint = lhs[tuple_index].type; } - check_expr_base(c, &o, rhs[i], type_hint); + check_expr_base(c, &o, rhs_expr, type_hint); if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); o.mode = Addressing_Invalid; @@ -5022,8 +5013,8 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array } } else { TypeTuple *tuple = &o.type->Tuple; - for_array(j, tuple->variables) { - o.type = tuple->variables[j]->type; + for (Entity *e : tuple->variables) { + o.type = e->type; array_add(operands, o); } @@ -5115,8 +5106,8 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } } else { TypeTuple *tuple = &o.type->Tuple; - for_array(j, tuple->variables) { - o.type = tuple->variables[j]->type; + for (Entity *e : tuple->variables) { + o.type = e->type; array_add(operands, o); } @@ -5459,8 +5450,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); auto ordered_operands = array_make(temporary_allocator(), param_count); defer ({ - for_array(i, ordered_operands) { - Operand const &o = ordered_operands[i]; + for (Operand const &o : ordered_operands) { if (o.expr != nullptr) { call->viral_state_flags |= o.expr->viral_state_flags; } @@ -5778,8 +5768,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op param_tuple = &pt->params->Tuple; } if (param_tuple != nullptr) { - for_array(i, param_tuple->variables) { - Entity *e = param_tuple->variables[i]; + for (Entity *e : param_tuple->variables) { if (is_blank_ident(e->token)) { continue; } @@ -5789,8 +5778,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } } else { Array procs = proc_group_entities(c, *operand); - for_array(j, procs) { - Type *proc_type = base_type(procs[j]->type); + for (Entity *proc : procs) { + Type *proc_type = base_type(proc->type); if (is_type_proc(proc_type)) { TypeProc *pt = &proc_type->Proc; TypeTuple *param_tuple = nullptr; @@ -5800,8 +5789,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (param_tuple == nullptr) { continue; } - for_array(i, param_tuple->variables) { - Entity *e = param_tuple->variables[i]; + for (Entity *e : param_tuple->variables) { if (is_blank_ident(e->token)) { continue; } @@ -5865,10 +5853,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (procs.count > 1) { isize max_arg_count = args.count; - for_array(i, args) { + for (Ast *arg : args) { // NOTE(bill): The only thing that may have multiple values // will be a call expression (assuming `or_return` and `()` will be stripped) - Ast *arg = strip_or_return_expr(args[i]); + arg = strip_or_return_expr(arg); if (arg && arg->kind == Ast_CallExpr) { max_arg_count = ISIZE_MAX; break; @@ -5931,8 +5919,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op // where the same positional parameter has the same type value (and ellipsis) bool proc_arg_count_all_equal = true; isize proc_arg_count = -1; - for_array(i, procs) { - Entity *p = procs[i]; + for (Entity *p : procs) { Type *pt = base_type(p->type); if (pt != nullptr && is_type_proc(pt)) { if (proc_arg_count < 0) { @@ -5954,8 +5941,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count); for (isize param_index = 0; param_index < lhs_count; param_index++) { Entity *e = nullptr; - for_array(j, procs) { - Entity *p = procs[j]; + for (Entity *p : procs) { Type *pt = base_type(p->type); if (pt != nullptr && is_type_proc(pt)) { if (e == nullptr) { @@ -5996,8 +5982,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op auto proc_entities = array_make(heap_allocator(), 0, procs.count*2 + 1); defer (array_free(&proc_entities)); - for_array(i, procs) { - array_add(&proc_entities, procs[i]); + for (Entity *proc : procs) { + array_add(&proc_entities, proc); } @@ -6087,8 +6073,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (procs.count > 0) { error_line("Did you mean to use one of the following:\n"); } - for_array(i, procs) { - Entity *proc = procs[i]; + for (Entity *proc : procs) { TokenPos pos = proc->token.pos; Type *t = base_type(proc->type); if (t == t_invalid) continue; @@ -6647,8 +6632,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (args.count > 0) { bool fail = false; bool first_is_field_value = (args[0]->kind == Ast_FieldValue); - for_array(i, args) { - Ast *arg = args[i]; + for (Ast *arg : args) { bool mix = false; if (first_is_field_value) { mix = arg->kind != Ast_FieldValue; @@ -6669,8 +6653,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } if (operand->mode == Addressing_Invalid) { - for_array(i, args) { - Ast *arg = args[i]; + for (Ast *arg : args) { if (arg->kind == Ast_FieldValue) { arg = arg->FieldValue.value; } @@ -7166,9 +7149,7 @@ gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, A Type *union_type = base_type(th); auto operands = array_make(temporary_allocator(), 0, union_type->Union.variants.count); - for_array(i, union_type->Union.variants) { - Type *vt = union_type->Union.variants[i]; - + for (Type *vt : union_type->Union.variants) { Operand x = {}; if (attempt_implicit_selector_expr(c, &x, ise, vt)) { array_add(&operands, x); @@ -7398,8 +7379,7 @@ gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind u } bool found = false; - for_array(j, bt->Enum.fields) { - Entity *f = bt->Enum.fields[j]; + for (Entity *f : bt->Enum.fields) { GB_ASSERT(f->kind == Entity_Constant); i64 fv = exact_value_to_i64(f->Constant.value); @@ -7917,8 +7897,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (cl->elems[0]->kind == Ast_FieldValue) { bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); continue; @@ -8070,8 +8049,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * RangeCache rc = range_cache_make(heap_allocator()); defer (range_cache_destroy(&rc)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); continue; @@ -8252,8 +8230,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * { Type *bt = base_type(index_type); GB_ASSERT(bt->kind == Type_Enum); - for_array(i, bt->Enum.fields) { - Entity *f = bt->Enum.fields[i]; + for (Entity *f : bt->Enum.fields) { if (f->kind != Entity_Constant) { continue; } @@ -8288,8 +8265,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * RangeCache rc = range_cache_make(heap_allocator()); defer (range_cache_destroy(&rc)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); continue; @@ -8453,8 +8429,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * auto unhandled = array_make(temporary_allocator(), 0, fields.count); - for_array(i, fields) { - Entity *f = fields[i]; + for (Entity *f : fields) { if (f->kind != Entity_Constant) { continue; } @@ -8580,8 +8555,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * bool key_is_typeid = is_type_typeid(t->Map.key); bool value_is_typeid = is_type_typeid(t->Map.value); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Only 'field = value' elements are allowed in a map literal"); continue; @@ -8630,8 +8604,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); is_constant = false; } else { - for_array(index, cl->elems) { - Ast *elem = cl->elems[index]; + for (Ast *elem : cl->elems) { if (elem->kind == Ast_FieldValue) { error(elem, "'field = value' in a bit_set a literal is not allowed"); continue; @@ -8683,8 +8656,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * BigInt one = {}; big_int_from_u64(&one, 1); - for_array(i, cl->elems) { - Ast *e = cl->elems[i]; + for (Ast *e : cl->elems) { GB_ASSERT(e->kind != Ast_FieldValue); TypeAndValue tav = e->tav; @@ -8783,8 +8755,7 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no if (bsrc->Union.variants.count != 1 && type_hint != nullptr) { bool allowed = false; - for_array(i, bsrc->Union.variants) { - Type *vt = bsrc->Union.variants[i]; + for (Type *vt : bsrc->Union.variants) { if (are_types_identical(vt, type_hint)) { allowed = true; add_type_info_type(c, vt); @@ -8817,8 +8788,7 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no if (is_type_union(src)) { bool ok = false; - for_array(i, bsrc->Union.variants) { - Type *vt = bsrc->Union.variants[i]; + for (Type *vt : bsrc->Union.variants) { if (are_types_identical(vt, dst)) { ok = true; break; @@ -8978,8 +8948,7 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast if (ce->args.count > 0) { bool fail = false; bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); - for_array(i, ce->args) { - Ast *arg = ce->args[i]; + for (Ast *arg : ce->args) { bool mix = false; if (first_is_field_value) { mix = arg->kind != Ast_FieldValue; @@ -9881,12 +9850,9 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { if (cl->elems.count == 0) { return true; } else { - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; + for (Ast *elem : cl->elems) { if (elem->tav.mode != Addressing_Constant) { - // if (elem->tav.value.kind != ExactValue_Invalid) { return false; - // } } if (!is_exact_value_zero(elem->tav.value)) { return false; @@ -10366,8 +10332,7 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan bool parens_needed = false; if (pt->results && pt->results->kind == Ast_FieldList) { - for_array(i, pt->results->FieldList.list) { - Ast *field = pt->results->FieldList.list[i]; + for (Ast *field : pt->results->FieldList.list) { ast_node(f, Field, field); if (f->names.count != 0) { parens_needed = true; -- cgit v1.2.3 From c7a704d345e9bda38da18807a1d7cd5bc5accc17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 15:26:47 +0000 Subject: Use `RwMutex` for the `Scope` --- src/check_decl.cpp | 12 ++++--- src/check_expr.cpp | 4 ++- src/check_stmt.cpp | 5 ++- src/checker.cpp | 21 +++++++----- src/checker.hpp | 2 +- src/thread_pool.cpp | 27 ++++++++------- src/threading.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 29 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 66f16546c..4afde6e51 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -381,8 +381,8 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e if (found_scope == nullptr) { return; } - mutex_lock(&found_scope->mutex); - defer (mutex_unlock(&found_scope->mutex)); + rw_mutex_lock(&found_scope->mutex); + defer (rw_mutex_unlock(&found_scope->mutex)); // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the // original entity was still used check checked, but the checking was only @@ -1478,7 +1478,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de if (t->kind == Type_Struct) { Scope *scope = t->Struct.scope; GB_ASSERT(scope != nullptr); - MUTEX_GUARD_BLOCK(scope->mutex) for (auto const &entry : scope->elements) { + rw_mutex_lock(&scope->mutex); + for (auto const &entry : scope->elements) { Entity *f = entry.value; if (f->kind == Entity_Variable) { Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); @@ -1488,6 +1489,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de array_add(&using_entities, puv); } } + rw_mutex_unlock(&scope->mutex); } else { error(e->token, "'using' can only be applied to variables of type struct"); break; @@ -1496,7 +1498,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de } } - MUTEX_GUARD_BLOCK(ctx->scope->mutex) for (auto const &entry : using_entities) { + rw_mutex_lock(&ctx->scope->mutex); + for (auto const &entry : using_entities) { Entity *e = entry.e; Entity *uvar = entry.uvar; Entity *prev = scope_insert_no_mutex(ctx->scope, uvar); @@ -1506,6 +1509,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de break; } } + rw_mutex_unlock(&ctx->scope->mutex); bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c1787e7b6..d9ab328cb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -236,10 +236,12 @@ gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); defer (did_you_mean_destroy(&d)); - MUTEX_GUARD_BLOCK(&scope->mutex) for (auto const &entry : scope->elements) { + rw_mutex_shared_lock(&scope->mutex); + for (auto const &entry : scope->elements) { Entity *e = entry.value; did_you_mean_append(&d, e->token.string); } + rw_mutex_shared_unlock(&scope->mutex); check_did_you_mean_print(&d, prefix); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e075297a4..6e84d0789 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -622,7 +622,10 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, case Entity_ImportName: { Scope *scope = e->ImportName.scope; - MUTEX_GUARD_BLOCK(scope->mutex) for (auto const &entry : scope->elements) { + rw_mutex_lock(&scope->mutex); + defer (rw_mutex_unlock(&scope->mutex)); + + for (auto const &entry : scope->elements) { String name = entry.key.string; Entity *decl = entry.value; if (!is_entity_exported(decl)) continue; diff --git a/src/checker.cpp b/src/checker.cpp index 0075fa543..1d536074d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -51,10 +51,11 @@ gb_internal bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *f gb_internal void scope_reset(Scope *scope) { if (scope == nullptr) return; - MUTEX_GUARD(&scope->mutex); + rw_mutex_lock(&scope->mutex); scope->head_child.store(nullptr, std::memory_order_relaxed); string_map_clear(&scope->elements); ptr_set_clear(&scope->imported); + rw_mutex_unlock(&scope->mutex); } gb_internal void scope_reserve(Scope *scope, isize capacity) { @@ -180,9 +181,9 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { gb_zero_item(d); d->parent = parent; d->scope = scope; - ptr_set_init(&d->deps); - ptr_set_init(&d->type_info_deps); - array_init (&d->labels, heap_allocator()); + ptr_set_init(&d->deps, 0); + ptr_set_init(&d->type_info_deps, 0); + d->labels.allocator = heap_allocator(); } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { @@ -394,9 +395,9 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s StringHashKey key = string_hash_string(name); for (Scope *s = scope; s != nullptr; s = s->parent) { Entity **found = nullptr; - mutex_lock(&s->mutex); + rw_mutex_shared_lock(&s->mutex); found = string_map_get(&s->elements, key); - mutex_unlock(&s->mutex); + rw_mutex_shared_unlock(&s->mutex); if (found) { Entity *e = *found; if (gone_thru_proc) { @@ -482,7 +483,7 @@ gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity Entity **found = nullptr; Entity *result = nullptr; - MUTEX_GUARD(&s->mutex); + rw_mutex_lock(&s->mutex); found = string_map_get(&s->elements, key); @@ -509,6 +510,8 @@ gb_internal Entity *scope_insert_with_name(Scope *s, String const &name, Entity entity->scope = s; } end:; + rw_mutex_unlock(&s->mutex); + return result; } @@ -669,7 +672,8 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) { Array vetted_entities = {}; array_init(&vetted_entities, heap_allocator()); - MUTEX_GUARD_BLOCK(scope->mutex) for (auto const &entry : scope->elements) { + rw_mutex_shared_lock(&scope->mutex); + for (auto const &entry : scope->elements) { Entity *e = entry.value; if (e == nullptr) continue; VettedEntity ve_unused = {}; @@ -686,6 +690,7 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) { array_add(&vetted_entities, ve_shadowed); } } + rw_mutex_shared_unlock(&scope->mutex); gb_sort(vetted_entities.data, vetted_entities.count, gb_size_of(VettedEntity), vetted_entity_variable_pos_cmp); diff --git a/src/checker.hpp b/src/checker.hpp index cc92fce28..53052d5cd 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -224,7 +224,7 @@ struct Scope { std::atomic next; std::atomic head_child; - BlockingMutex mutex; + RwMutex mutex; StringMap elements; PtrSet imported; diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 276e93dff..2c369eaad 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -47,7 +47,7 @@ gb_internal void thread_pool_destroy(ThreadPool *pool) { for_array_off(i, 1, pool->threads) { Thread *t = &pool->threads[i]; - pool->tasks_available.fetch_add(1, std::memory_order_release); + pool->tasks_available.fetch_add(1, std::memory_order_relaxed); futex_broadcast(&pool->tasks_available); thread_join_and_destroy(t); } @@ -74,7 +74,7 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) { } while (!thread->head_and_tail.compare_exchange_weak(capture, new_capture)); thread->pool->tasks_left.fetch_add(1, std::memory_order_release); - thread->pool->tasks_available.fetch_add(1, std::memory_order_release); + thread->pool->tasks_available.fetch_add(1, std::memory_order_relaxed); futex_broadcast(&thread->pool->tasks_available); } @@ -82,7 +82,7 @@ bool thread_pool_queue_pop(Thread *thread, WorkerTask *task) { u64 capture; u64 new_capture; do { - capture = thread->head_and_tail.load(); + capture = thread->head_and_tail.load(std::memory_order_acquire); u64 mask = thread->capacity - 1; u64 head = (capture >> 32) & mask; @@ -97,7 +97,7 @@ bool thread_pool_queue_pop(Thread *thread, WorkerTask *task) { *task = thread->queue[tail]; new_capture = (head << 32) | new_tail; - } while (!thread->head_and_tail.compare_exchange_weak(capture, new_capture)); + } while (!thread->head_and_tail.compare_exchange_weak(capture, new_capture, std::memory_order_release)); return true; } @@ -168,22 +168,21 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) { Thread *thread = &pool->threads.data[idx]; WorkerTask task; - if (!thread_pool_queue_pop(thread, &task)) { - continue; - } - task.do_work(task.data); - pool->tasks_left.fetch_sub(1, std::memory_order_release); + if (thread_pool_queue_pop(thread, &task)) { + task.do_work(task.data); + pool->tasks_left.fetch_sub(1, std::memory_order_release); - if (pool->tasks_left.load(std::memory_order_acquire) == 0) { - futex_signal(&pool->tasks_left); - } + if (pool->tasks_left.load(std::memory_order_acquire) == 0) { + futex_signal(&pool->tasks_left); + } - goto main_loop_continue; + goto main_loop_continue; + } } } // if we've done all our work, and there's nothing to steal, go to sleep - state = pool->tasks_available.load(); + state = pool->tasks_available.load(std::memory_order_acquire); futex_wait(&pool->tasks_available, state); main_loop_continue:; diff --git a/src/threading.cpp b/src/threading.cpp index 78943150e..27a17112e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -8,10 +8,12 @@ struct BlockingMutex; struct RecursiveMutex; +struct RwMutex; struct Semaphore; struct Condition; struct Thread; struct ThreadPool; +struct Parker; #define THREAD_PROC(name) isize name(struct Thread *thread) gb_internal THREAD_PROC(thread_pool_thread_proc); @@ -56,6 +58,13 @@ gb_internal void mutex_lock (RecursiveMutex *m); gb_internal bool mutex_try_lock(RecursiveMutex *m); gb_internal void mutex_unlock (RecursiveMutex *m); +gb_internal void rw_mutex_lock (RwMutex *m); +gb_internal bool rw_mutex_try_lock (RwMutex *m); +gb_internal void rw_mutex_unlock (RwMutex *m); +gb_internal void rw_mutex_shared_lock (RwMutex *m); +gb_internal bool rw_mutex_try_shared_lock(RwMutex *m); +gb_internal void rw_mutex_shared_unlock (RwMutex *m); + gb_internal void semaphore_post (Semaphore *s, i32 count); gb_internal void semaphore_wait (Semaphore *s); gb_internal void semaphore_release(Semaphore *s) { semaphore_post(s, 1); } @@ -65,6 +74,10 @@ gb_internal void condition_broadcast(Condition *c); gb_internal void condition_signal(Condition *c); gb_internal void condition_wait(Condition *c, BlockingMutex *m); +gb_internal void park(Parker *p); +gb_internal void unpark_one(Parker *p); +gb_internal void unpark_all(Parker *p); + gb_internal u32 thread_current_id(void); gb_internal void thread_init (ThreadPool *pool, Thread *t, isize idx); @@ -205,6 +218,30 @@ gb_internal void semaphore_wait(Semaphore *s) { gb_internal void condition_wait(Condition *c, BlockingMutex *m) { SleepConditionVariableSRW(&c->cond, &m->srwlock, INFINITE, 0); } + + struct RwMutex { + SRWLOCK srwlock; + }; + + gb_internal void rw_mutex_lock(RwMutex *m) { + AcquireSRWLockExclusive(&m->srwlock); + } + gb_internal bool rw_mutex_try_lock(RwMutex *m) { + return !!TryAcquireSRWLockExclusive(&m->srwlock); + } + gb_internal void rw_mutex_unlock(RwMutex *m) { + ReleaseSRWLockExclusive(&m->srwlock); + } + + gb_internal void rw_mutex_shared_lock(RwMutex *m) { + AcquireSRWLockShared(&m->srwlock); + } + gb_internal bool rw_mutex_try_shared_lock(RwMutex *m) { + return !!TryAcquireSRWLockShared(&m->srwlock); + } + gb_internal void rw_mutex_shared_unlock(RwMutex *m) { + ReleaseSRWLockShared(&m->srwlock); + } #else enum Internal_Mutex_State : i32 { Internal_Mutex_State_Unlocked = 0, @@ -306,8 +343,67 @@ gb_internal void semaphore_wait(Semaphore *s) { futex_wait(&c->state(), state); mutex_lock(m); } + + struct RwMutex { + // TODO(bill): make this a proper RW mutex + BlockingMutex mutex; + }; + + gb_internal void rw_mutex_lock(RwMutex *m) { + mutex_lock(&m->mutex); + } + gb_internal bool rw_mutex_try_lock(RwMutex *m) { + return mutex_try_lock(&m->mutex); + } + gb_internal void rw_mutex_unlock(RwMutex *m) { + mutex_unlock(&m->mutex); + } + + gb_internal void rw_mutex_shared_lock(RwMutex *m) { + mutex_lock(&m->mutex); + } + gb_internal bool rw_mutex_try_shared_lock(RwMutex *m) { + return mutex_try_lock(&m->mutex); + } + gb_internal void rw_mutex_shared_unlock(RwMutex *m) { + mutex_unlock(&m->mutex); + } #endif +struct Parker { + Futex state; +}; +enum ParkerState : u32 { + ParkerState_Empty = 0, + ParkerState_Notified = 1, + ParkerState_Parked = UINT32_MAX, +}; + +gb_internal void park(Parker *p) { + if (p->state.fetch_sub(1, std::memory_order_acquire) == ParkerState_Notified) { + return; + } + for (;;) { + futex_wait(&p->state, ParkerState_Parked); + i32 notified = ParkerState_Empty; + if (p->state.compare_exchange_strong(notified, ParkerState_Empty, std::memory_order_acquire, std::memory_order_acquire)) { + return; + } + } +} + +gb_internal void unpark_one(Parker *p) { + if (p->state.exchange(ParkerState_Notified, std::memory_order_release) == ParkerState_Parked) { + futex_signal(&p->state); + } +} + +gb_internal void unpark_all(Parker *p) { + if (p->state.exchange(ParkerState_Notified, std::memory_order_release) == ParkerState_Parked) { + futex_broadcast(&p->state); + } +} + gb_internal u32 thread_current_id(void) { u32 thread_id; -- cgit v1.2.3 From 3dee3205b299b2a2e803a3bc248f0a9ffdcce69e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 15:34:52 +0000 Subject: Use `RwMutex` for `DeclInfo` `deps --- src/check_decl.cpp | 27 +++++++++++++++++---------- src/check_expr.cpp | 6 ++++-- src/checker.cpp | 8 ++++---- src/checker.hpp | 4 ++-- 4 files changed, 27 insertions(+), 18 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 4afde6e51..72c69b5dc 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1584,19 +1584,26 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de // NOTE(bill): Add the dependencies from the procedure literal (lambda) // But only at the procedure level - MUTEX_GUARD_BLOCK(decl->deps_mutex) - MUTEX_GUARD_BLOCK(decl->parent->deps_mutex) { - for (Entity *e : decl->deps) { - ptr_set_add(&decl->parent->deps, e); - } + rw_mutex_shared_lock(&decl->deps_mutex); + rw_mutex_lock(&decl->parent->deps_mutex); + + for (Entity *e : decl->deps) { + ptr_set_add(&decl->parent->deps, e); } - MUTEX_GUARD_BLOCK(decl->type_info_deps_mutex) - MUTEX_GUARD_BLOCK(decl->parent->type_info_deps_mutex) { - for (Type *t : decl->type_info_deps) { - ptr_set_add(&decl->parent->type_info_deps, t); - } + rw_mutex_unlock(&decl->parent->deps_mutex); + rw_mutex_shared_unlock(&decl->deps_mutex); + + + rw_mutex_shared_lock(&decl->type_info_deps_mutex); + rw_mutex_lock(&decl->parent->type_info_deps_mutex); + + for (Type *t : decl->type_info_deps) { + ptr_set_add(&decl->parent->type_info_deps, t); } + + rw_mutex_unlock(&decl->parent->type_info_deps_mutex); + rw_mutex_shared_unlock(&decl->type_info_deps_mutex); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d9ab328cb..e3cd66db6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4928,21 +4928,23 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) { if (lhs != nullptr && c->decl != nullptr) { - mutex_lock(&c->info->deps_mutex); + // mutex_lock(&c->info->deps_mutex); for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) { Entity *e = lhs[tuple_index + j]; if (e != nullptr) { DeclInfo *decl = decl_info_of_entity(e); if (decl != nullptr) { + rw_mutex_lock(&c->decl->deps_mutex); for (Entity *dep : decl->deps) { ptr_set_add(&c->decl->deps, dep); } + rw_mutex_unlock(&c->decl->deps_mutex); } } } - mutex_unlock(&c->info->deps_mutex); + // mutex_unlock(&c->info->deps_mutex); } return tuple_count; } diff --git a/src/checker.cpp b/src/checker.cpp index 1d536074d..fd80d07de 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -744,17 +744,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) { gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { - mutex_lock(&d->deps_mutex); + rw_mutex_lock(&d->deps_mutex); ptr_set_add(&d->deps, e); - mutex_unlock(&d->deps_mutex); + rw_mutex_unlock(&d->deps_mutex); } gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) { if (d == nullptr) { return; } - mutex_lock(&d->type_info_deps_mutex); + rw_mutex_lock(&d->type_info_deps_mutex); ptr_set_add(&d->type_info_deps, type); - mutex_unlock(&d->type_info_deps_mutex); + rw_mutex_unlock(&d->type_info_deps_mutex); } gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { diff --git a/src/checker.hpp b/src/checker.hpp index 53052d5cd..50f4a204c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -179,10 +179,10 @@ struct DeclInfo { CommentGroup *comment; CommentGroup *docs; - BlockingMutex deps_mutex; + RwMutex deps_mutex; PtrSet deps; - BlockingMutex type_info_deps_mutex; + RwMutex type_info_deps_mutex; PtrSet type_info_deps; Array labels; -- cgit v1.2.3 From 485c6066724b374de5b94115411f529493f799f7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 15:37:35 +0000 Subject: Clarify `RwLock`s for `add_dependenies_from_unpacking` --- src/check_expr.cpp | 6 ++---- src/checker.hpp | 6 ------ 2 files changed, 2 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e3cd66db6..38fe33c24 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4928,23 +4928,21 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) { if (lhs != nullptr && c->decl != nullptr) { - // mutex_lock(&c->info->deps_mutex); - for (isize j = 0; (tuple_index + j) < lhs_count && j < tuple_count; j++) { Entity *e = lhs[tuple_index + j]; if (e != nullptr) { DeclInfo *decl = decl_info_of_entity(e); if (decl != nullptr) { + rw_mutex_shared_lock(&decl->deps_mutex); rw_mutex_lock(&c->decl->deps_mutex); for (Entity *dep : decl->deps) { ptr_set_add(&c->decl->deps, dep); } rw_mutex_unlock(&c->decl->deps_mutex); + rw_mutex_shared_unlock(&decl->deps_mutex); } } } - - // mutex_unlock(&c->info->deps_mutex); } return tuple_count; } diff --git a/src/checker.hpp b/src/checker.hpp index 50f4a204c..554c8ddf4 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -357,12 +357,6 @@ struct CheckerInfo { BlockingMutex global_untyped_mutex; BlockingMutex builtin_mutex; - // NOT recursive & only used at the end of `check_proc_body` - // and in `add_dependency`. - // This is a possible source of contention but probably not - // too much of a problem in practice - BlockingMutex deps_mutex; - BlockingMutex type_and_value_mutex; RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files -- cgit v1.2.3 From 774fea1e63941473b9899a50585e0f171184a147 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 15:47:25 +0000 Subject: Use `RwMutex` for `gen_procs` --- src/check_expr.cpp | 16 ++++++++-------- src/checker.cpp | 13 +++++++------ src/checker.hpp | 11 +++-------- src/llvm_backend_stmt.cpp | 3 ++- 4 files changed, 20 insertions(+), 23 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 38fe33c24..746a29ce0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -440,11 +440,11 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E auto *found = map_get(&info->gen_procs, base_entity->identifier.load()); if (found) { gen_procs = *found; - mutex_lock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_lock(&gen_procs->mutex); // @local-mutex for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { - mutex_unlock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex // @@GPM //////////////////////////// mutex_unlock(&info->gen_procs_mutex); ///////////////////////////////////// @@ -455,7 +455,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } - mutex_unlock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex } else { gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); gen_procs->procs.allocator = heap_allocator(); @@ -481,11 +481,11 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return false; } - mutex_lock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_lock(&gen_procs->mutex); // @local-mutex for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { - mutex_unlock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex if (poly_proc_data) { poly_proc_data->gen_entity = other; @@ -509,7 +509,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } - mutex_unlock(&gen_procs->mutex); // @local-mutex + rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex } @@ -569,9 +569,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E } } - mutex_lock(&gen_procs->mutex); // @local-mutex + rw_mutex_lock(&gen_procs->mutex); // @local-mutex array_add(&gen_procs->procs, entity); - mutex_unlock(&gen_procs->mutex); // @local-mutex + rw_mutex_unlock(&gen_procs->mutex); // @local-mutex ProcInfo *proc_info = gb_alloc_item(permanent_allocator(), ProcInfo); proc_info->file = file; diff --git a/src/checker.cpp b/src/checker.cpp index fd80d07de..3f5c2892f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1356,9 +1356,9 @@ gb_internal ExprInfo *check_get_expr_info(CheckerContext *c, Ast *expr) { } return nullptr; } else { - mutex_lock(&c->info->global_untyped_mutex); - defer (mutex_unlock(&c->info->global_untyped_mutex)); + rw_mutex_shared_lock(&c->info->global_untyped_mutex); ExprInfo **found = map_get(&c->info->global_untyped, expr); + rw_mutex_shared_unlock(&c->info->global_untyped_mutex); if (found) { return *found; } @@ -1370,9 +1370,9 @@ gb_internal void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMod if (c->untyped != nullptr) { map_set(c->untyped, expr, make_expr_info(mode, type, value, false)); } else { - mutex_lock(&c->info->global_untyped_mutex); + rw_mutex_lock(&c->info->global_untyped_mutex); map_set(&c->info->global_untyped, expr, make_expr_info(mode, type, value, false)); - mutex_unlock(&c->info->global_untyped_mutex); + rw_mutex_unlock(&c->info->global_untyped_mutex); } } @@ -1382,10 +1382,10 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { GB_ASSERT(map_get(c->untyped, e) == nullptr); } else { auto *untyped = &c->info->global_untyped; - mutex_lock(&c->info->global_untyped_mutex); + rw_mutex_lock(&c->info->global_untyped_mutex); map_remove(untyped, e); GB_ASSERT(map_get(untyped, e) == nullptr); - mutex_unlock(&c->info->global_untyped_mutex); + rw_mutex_unlock(&c->info->global_untyped_mutex); } } @@ -1454,6 +1454,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo BlockingMutex *mutex = &ctx->info->type_and_value_mutex; if (ctx->pkg) { + // TODO(bill): is a per package mutex is a good idea here? mutex = &ctx->pkg->type_and_value_mutex; } diff --git a/src/checker.hpp b/src/checker.hpp index 554c8ddf4..226f69c1c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -317,7 +317,7 @@ struct LoadFileCache { struct GenProcsData { Array procs; - BlockingMutex mutex; + RwMutex mutex; }; // CheckerInfo stores all the symbol information for a type-checked program @@ -347,14 +347,9 @@ struct CheckerInfo { // Below are accessed within procedures - // NOTE(bill): If the semantic checker (check_proc_body) is to ever to be multithreaded, - // these variables will be of contention - - Semaphore collect_semaphore; - + RwMutex global_untyped_mutex; UntypedExprInfoMap global_untyped; // NOTE(bill): This needs to be a map and not on the Ast // as it needs to be iterated across afterwards - BlockingMutex global_untyped_mutex; BlockingMutex builtin_mutex; BlockingMutex type_and_value_mutex; @@ -388,7 +383,7 @@ struct CheckerInfo { BlockingMutex load_file_mutex; StringMap load_file_cache; - BlockingMutex all_procedures_mutex;; + BlockingMutex all_procedures_mutex; Array all_procedures; }; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index c48115079..1660d3487 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -57,7 +57,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) auto *found = map_get(&info->gen_procs, ident); if (found) { GenProcsData *gpd = *found; - MUTEX_GUARD(&gpd->mutex); + rw_mutex_shared_lock(&gpd->mutex); for (Entity *e : gpd->procs) { if (!ptr_set_exists(min_dep_set, e)) { continue; @@ -65,6 +65,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) DeclInfo *d = decl_info_of_entity(e); lb_build_nested_proc(p, &d->proc_lit->ProcLit, e); } + rw_mutex_shared_unlock(&gpd->mutex); } else { lb_build_nested_proc(p, pl, e); } -- cgit v1.2.3 From 855ebceadcc4612a6451f268ab6d6693838ed5f4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 3 Jan 2023 17:26:05 +0000 Subject: Minimize `add_type_info_type` usage --- src/check_builtin.cpp | 2 +- src/check_expr.cpp | 8 ++++---- src/check_stmt.cpp | 8 +++++--- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7c5521dde..606283c32 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3573,7 +3573,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Entity *base_type_entity = alloc_entity_type_name(scope, token, elem, EntityState_Resolved); add_entity(c, scope, nullptr, base_type_entity); - add_type_info_type(c, soa_struct); + // add_type_info_type(c, soa_struct); operand->type = soa_struct; break; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 746a29ce0..5f28504a2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8779,8 +8779,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - add_type_info_type(c, o->type); - add_type_info_type(c, bsrc->Union.variants[0]); + // add_type_info_type(c, o->type); + // add_type_info_type(c, bsrc->Union.variants[0]); o->type = bsrc->Union.variants[0]; o->mode = Addressing_OptionalOk; @@ -8812,8 +8812,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - add_type_info_type(c, o->type); - add_type_info_type(c, t); + // add_type_info_type(c, o->type); + // add_type_info_type(c, t); o->type = t; o->mode = Addressing_OptionalOk; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6e84d0789..9547035d0 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1132,7 +1132,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ check_expr(ctx, &x, rhs); check_assignment(ctx, &x, nullptr, str_lit("type switch expression")); - add_type_info_type(ctx, x.type); + // add_type_info_type(ctx, x.type); TypeSwitchKind switch_kind = check_valid_type_switch_type(x.type); if (switch_kind == TypeSwitch_Invalid) { @@ -1223,7 +1223,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ continue; } case_type = y.type; - add_type_info_type(ctx, y.type); + // add_type_info_type(ctx, y.type); } else if (switch_kind == TypeSwitch_Any) { case_type = y.type; add_type_info_type(ctx, y.type); @@ -1259,7 +1259,9 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ if (case_type == nullptr) { case_type = x.type; } - add_type_info_type(ctx, case_type); + if (switch_kind == TypeSwitch_Any) { + add_type_info_type(ctx, case_type); + } check_open_scope(ctx, stmt); { -- cgit v1.2.3 From 12e42d92d30b3a9cf4d7bb7bb17a2e031285073b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 4 Jan 2023 15:35:24 +0000 Subject: Localize `GenProcsData` to the entity itself --- src/check_expr.cpp | 29 ++++++++++++++--------------- src/checker.cpp | 4 ++-- src/checker.hpp | 2 -- src/entity.cpp | 5 ++++- src/llvm_backend_stmt.cpp | 6 ++---- 5 files changed, 22 insertions(+), 24 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5f28504a2..bce16f304 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -366,8 +366,6 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E GB_ASSERT(dst == nullptr); } - // MUTEX_GUARD(&info->gen_procs_mutex); - if (!src->Proc.is_polymorphic || src->Proc.is_poly_specialized) { return false; } @@ -434,20 +432,21 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E GenProcsData *gen_procs = nullptr; - // @@GPM ////////////////////////// - mutex_lock(&info->gen_procs_mutex); - /////////////////////////////////// - auto *found = map_get(&info->gen_procs, base_entity->identifier.load()); - if (found) { - gen_procs = *found; + GB_ASSERT(base_entity->identifier.load()->kind == Ast_Ident); + GB_ASSERT(base_entity->kind == Entity_Procedure); + + + mutex_lock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex + + gen_procs = base_entity->Procedure.gen_procs; + if (gen_procs) { rw_mutex_shared_lock(&gen_procs->mutex); // @local-mutex + for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex - // @@GPM //////////////////////////// - mutex_unlock(&info->gen_procs_mutex); - ///////////////////////////////////// + mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex if (poly_proc_data) { poly_proc_data->gen_entity = other; @@ -455,15 +454,15 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E return true; } } + rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex } else { gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); gen_procs->procs.allocator = heap_allocator(); - map_set(&info->gen_procs, base_entity->identifier.load(), gen_procs); + base_entity->Procedure.gen_procs = gen_procs; } - // @@GPM //////////////////////////// - mutex_unlock(&info->gen_procs_mutex); - ///////////////////////////////////// + + mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex { // LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice diff --git a/src/checker.cpp b/src/checker.cpp index 5fc9a5551..0bebce232 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1143,7 +1143,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->entities, a); map_init(&i->global_untyped); string_map_init(&i->foreigns); - map_init(&i->gen_procs); + // map_init(&i->gen_procs); map_init(&i->gen_types); array_init(&i->type_info_types, a); map_init(&i->type_info_map); @@ -1172,7 +1172,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->entities); map_destroy(&i->global_untyped); string_map_destroy(&i->foreigns); - map_destroy(&i->gen_procs); + // map_destroy(&i->gen_procs); map_destroy(&i->gen_types); array_free(&i->type_info_types); map_destroy(&i->type_info_map); diff --git a/src/checker.hpp b/src/checker.hpp index 92926689e..8b8819d97 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -368,9 +368,7 @@ struct CheckerInfo { RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files - BlockingMutex gen_procs_mutex; RwMutex gen_types_mutex; - PtrMap gen_procs; // Key: Ast * | Identifier -> Entity PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive diff --git a/src/entity.cpp b/src/entity.cpp index f82a2fb05..b92ba825f 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -130,7 +130,7 @@ enum EntityConstantFlags : u32 { EntityConstantFlag_ImplicitEnumValue = 1<<0, }; -enum ProcedureOptimizationMode : u32 { +enum ProcedureOptimizationMode : u8 { ProcedureOptimizationMode_Default, ProcedureOptimizationMode_None, ProcedureOptimizationMode_Minimal, @@ -233,6 +233,9 @@ struct Entity { String link_name; String link_prefix; DeferredProcedure deferred_procedure; + + struct GenProcsData *gen_procs; + BlockingMutex gen_procs_mutex; ProcedureOptimizationMode optimization_mode; bool is_foreign : 1; bool is_export : 1; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 1660d3487..0e6f75118 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -50,13 +50,11 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) continue; // It's an alias } - CheckerInfo *info = p->module->info; DeclInfo *decl = decl_info_of_entity(e); ast_node(pl, ProcLit, decl->proc_lit); if (pl->body != nullptr) { - auto *found = map_get(&info->gen_procs, ident); - if (found) { - GenProcsData *gpd = *found; + GenProcsData *gpd = e->Procedure.gen_procs; + if (gpd) { rw_mutex_shared_lock(&gpd->mutex); for (Entity *e : gpd->procs) { if (!ptr_set_exists(min_dep_set, e)) { -- cgit v1.2.3 From 8a99b8af3e875141156d359026b785fcfd284f57 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 4 Jan 2023 15:55:10 +0000 Subject: Narrow mutex usage --- src/check_expr.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bce16f304..e9e61486e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -435,18 +435,17 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E GB_ASSERT(base_entity->identifier.load()->kind == Ast_Ident); GB_ASSERT(base_entity->kind == Entity_Procedure); - mutex_lock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex - gen_procs = base_entity->Procedure.gen_procs; if (gen_procs) { rw_mutex_shared_lock(&gen_procs->mutex); // @local-mutex + mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex + for (Entity *other : gen_procs->procs) { Type *pt = base_type(other->type); if (are_types_identical(pt, final_proc_type)) { rw_mutex_shared_unlock(&gen_procs->mutex); // @local-mutex - mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex if (poly_proc_data) { poly_proc_data->gen_entity = other; @@ -460,9 +459,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E gen_procs = gb_alloc_item(permanent_allocator(), GenProcsData); gen_procs->procs.allocator = heap_allocator(); base_entity->Procedure.gen_procs = gen_procs; + mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex } - mutex_unlock(&base_entity->Procedure.gen_procs_mutex); // @entity-mutex { // LEAK TODO(bill): This is technically a memory leak as it has to generate the type twice -- cgit v1.2.3 From 1517f1d7793c8985664600a820e3434dfdf83810 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 5 Jan 2023 11:54:21 +0000 Subject: Add uncomment `add_type_info_type` calls for type assertions --- src/check_decl.cpp | 60 ++++++++++++++++++++++++++++------------------------ src/check_expr.cpp | 8 +++---- src/checker.cpp | 38 +++++---------------------------- src/llvm_backend.cpp | 1 + src/ptr_map.cpp | 29 +++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 65 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 644771dcd..d4ae9c59d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1411,6 +1411,37 @@ end:; } +gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) { + if (decl && decl->parent) { + Scope *ps = decl->parent->scope; + if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { + return; + } else { + // NOTE(bill): Add the dependencies from the procedure literal (lambda) + // But only at the procedure level + rw_mutex_shared_lock(&decl->deps_mutex); + rw_mutex_lock(&decl->parent->deps_mutex); + + for (Entity *e : decl->deps) { + ptr_set_add(&decl->parent->deps, e); + } + + rw_mutex_unlock(&decl->parent->deps_mutex); + rw_mutex_shared_unlock(&decl->deps_mutex); + + rw_mutex_shared_lock(&decl->type_info_deps_mutex); + rw_mutex_lock(&decl->parent->type_info_deps_mutex); + + for (Type *t : decl->type_info_deps) { + ptr_set_add(&decl->parent->type_info_deps, t); + } + + rw_mutex_unlock(&decl->parent->type_info_deps_mutex); + rw_mutex_shared_unlock(&decl->type_info_deps_mutex); + } + } +} + struct ProcUsingVar { Entity *e; Entity *uvar; @@ -1576,34 +1607,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_scope_usage(ctx->checker, ctx->scope); - // if (decl->parent) { - // Scope *ps = decl->parent->scope; - // if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - // return true; - // } else { - // // NOTE(bill): Add the dependencies from the procedure literal (lambda) - // // But only at the procedure level - // rw_mutex_shared_lock(&decl->deps_mutex); - // rw_mutex_lock(&decl->parent->deps_mutex); - - // for (Entity *e : decl->deps) { - // ptr_set_add(&decl->parent->deps, e); - // } - - // rw_mutex_unlock(&decl->parent->deps_mutex); - // rw_mutex_shared_unlock(&decl->deps_mutex); - - // rw_mutex_shared_lock(&decl->type_info_deps_mutex); - // rw_mutex_lock(&decl->parent->type_info_deps_mutex); - - // for (Type *t : decl->type_info_deps) { - // ptr_set_add(&decl->parent->type_info_deps, t); - // } - - // rw_mutex_unlock(&decl->parent->type_info_deps_mutex); - // rw_mutex_shared_unlock(&decl->type_info_deps_mutex); - // } - // } + add_deps_from_child_to_parent(decl); return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e9e61486e..e0519d26b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8777,8 +8777,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - // add_type_info_type(c, o->type); - // add_type_info_type(c, bsrc->Union.variants[0]); + add_type_info_type(c, o->type); + add_type_info_type(c, bsrc->Union.variants[0]); o->type = bsrc->Union.variants[0]; o->mode = Addressing_OptionalOk; @@ -8810,8 +8810,8 @@ gb_internal ExprKind check_type_assertion(CheckerContext *c, Operand *o, Ast *no return kind; } - // add_type_info_type(c, o->type); - // add_type_info_type(c, t); + add_type_info_type(c, o->type); + add_type_info_type(c, t); o->type = t; o->mode = Addressing_OptionalOk; diff --git a/src/checker.cpp b/src/checker.cpp index 8cb6ea99d..a2ed73119 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2026,14 +2026,13 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { ti_index = type_info_index(&c->info, t, false); } GB_ASSERT(ti_index >= 0); - if (map_get(set, ti_index)) { - // Type already exists; - return; - } // IMPORTANT NOTE(bill): this must be copied as `map_set` takes a const ref // and effectively assigns the `+1` of the value isize const count = set->entries.count; - map_set(set, ti_index, count); + if (map_set_if_not_previously_exists(set, ti_index, count)) { + // Type already exists; + return; + } // Add nested types if (t->kind == Type_Named) { @@ -5650,34 +5649,7 @@ gb_internal void check_walk_all_dependencies(DeclInfo *decl) { for (DeclInfo *child = decl->next_child; child != nullptr; child = child->next_sibling) { check_walk_all_dependencies(child); } - if (decl->parent && decl->parent->entity && decl->parent->entity->kind == Entity_Procedure) { - Scope *ps = decl->parent->scope; - if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) { - return; - } else { - // NOTE(bill): Add the dependencies from the procedure literal (lambda) - // But only at the procedure level - rw_mutex_shared_lock(&decl->deps_mutex); - rw_mutex_lock(&decl->parent->deps_mutex); - - for (Entity *e : decl->deps) { - ptr_set_add(&decl->parent->deps, e); - } - - rw_mutex_unlock(&decl->parent->deps_mutex); - rw_mutex_shared_unlock(&decl->deps_mutex); - - rw_mutex_shared_lock(&decl->type_info_deps_mutex); - rw_mutex_lock(&decl->parent->type_info_deps_mutex); - - for (Type *t : decl->type_info_deps) { - ptr_set_add(&decl->parent->type_info_deps, t); - } - - rw_mutex_unlock(&decl->parent->type_info_deps_mutex); - rw_mutex_shared_unlock(&decl->type_info_deps_mutex); - } - } + add_deps_from_child_to_parent(decl); } gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 304e5ef36..192e5cc56 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1920,6 +1920,7 @@ gb_internal void lb_generate_code(lbGenerator *gen) { if (!ptr_set_exists(min_dep_set, e)) { continue; } + DeclInfo *decl = decl_info_of_entity(e); if (decl == nullptr) { continue; diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index c33bf9ffb..89d2cbf9d 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -52,6 +52,7 @@ template gb_internal void map_init (PtrMap< template gb_internal void map_destroy (PtrMap *h); template gb_internal V * map_get (PtrMap *h, K key); template gb_internal void map_set (PtrMap *h, K key, V const &value); +template gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value); // returns true if it previously existed template gb_internal void map_remove (PtrMap *h, K key); template gb_internal void map_clear (PtrMap *h); template gb_internal void map_grow (PtrMap *h); @@ -240,6 +241,34 @@ gb_internal void map_set(PtrMap *h, K key, V const &value) { } } +// returns true if it previously existed +template +gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value) { + MapIndex index; + MapFindResult fr; + if (h->hashes.count == 0) { + map_grow(h); + } + fr = map__find(h, key); + if (fr.entry_index != MAP_SENTINEL) { + return true; + } else { + index = map__add_entry(h, key); + if (fr.entry_prev != MAP_SENTINEL) { + h->entries.data[fr.entry_prev].next = index; + } else { + h->hashes.data[fr.hash_index] = index; + } + } + h->entries.data[index].value = value; + + if (map__full(h)) { + map_grow(h); + } + return false; +} + + template gb_internal void map__erase(PtrMap *h, MapFindResult const &fr) { MapFindResult last; -- cgit v1.2.3 From 520ff731de908f63c8f5fe21ea058b8590d4285d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Jan 2023 00:47:20 +0000 Subject: Add `ArenaTemp` to the compiler --- src/big_int.cpp | 1 + src/build_settings.cpp | 1 + src/check_builtin.cpp | 2 ++ src/check_decl.cpp | 1 + src/check_expr.cpp | 37 ++++++++++++++++++++-------- src/check_stmt.cpp | 7 ++++++ src/common.cpp | 4 +++ src/common_memory.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-- 8 files changed, 107 insertions(+), 12 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/big_int.cpp b/src/big_int.cpp index 0f6b921b2..36652005e 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -477,6 +477,7 @@ gb_internal void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) { } gb_internal void debug_print_big_int(BigInt const *x) { + TEMPORARY_ALLOCATOR_GUARD(); String s = big_int_to_string(temporary_allocator(), x, 10); gb_printf_err("[DEBUG] %.*s\n", LIT(s)); } diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 0640c7982..122a010b2 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1045,6 +1045,7 @@ gb_internal bool has_asm_extension(String const &path) { // temporary gb_internal char *token_pos_to_string(TokenPos const &pos) { + TEMPORARY_ALLOCATOR_GUARD(); gbString s = gb_string_make_reserve(temporary_allocator(), 128); String file = get_file_path_string(pos.file_id); switch (build_context.ODIN_ERROR_POS_STYLE) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 294bc7da8..a7d5536e7 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1118,6 +1118,7 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String } }); + TEMPORARY_ALLOCATOR_GUARD(); char *c_str = alloc_cstring(temporary_allocator(), path); gbFile f = {}; @@ -3062,6 +3063,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } case BuiltinProc_soa_zip: { + TEMPORARY_ALLOCATOR_GUARD(); auto types = array_make(temporary_allocator(), 0, ce->args.count); auto names = array_make(temporary_allocator(), 0, ce->args.count); diff --git a/src/check_decl.cpp b/src/check_decl.cpp index d4ae9c59d..8f4534fb9 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -117,6 +117,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation + TEMPORARY_ALLOCATOR_GUARD(); auto operands = array_make(temporary_allocator(), 0, 2*lhs_count); check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e0519d26b..c1fa21dc4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -86,6 +86,7 @@ gb_internal Entity * find_polymorphic_record_entity (CheckerContext *c, Type *or gb_internal void check_not_tuple (CheckerContext *c, Operand *operand); gb_internal void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gb_internal gbString expr_to_string (Ast *expression); +gb_internal gbString expr_to_string (Ast *expression, gbAllocator allocator); gb_internal void update_untyped_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); gb_internal bool check_is_terminating (Ast *node, String const &label); gb_internal bool check_has_break (Ast *stmt, String const &label, bool implicit); @@ -2404,8 +2405,8 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok if (x->type == err_type && is_operand_nil(*x)) { err_type = y->type; } - gbString type_string = type_to_string(err_type); - defer (gb_string_free(type_string)); + TEMPORARY_ALLOCATOR_GUARD(); + gbString type_string = type_to_string(err_type, temporary_allocator()); err_str = gb_string_make(temporary_allocator(), gb_bprintf("operator '%.*s' not defined for type '%s'", LIT(token_strings[op]), type_string)); } else { @@ -2417,20 +2418,19 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok add_comparison_procedures_for_fields(c, comparison_type); } } else { + TEMPORARY_ALLOCATOR_GUARD(); gbString xt, yt; if (x->mode == Addressing_ProcGroup) { - xt = gb_string_make(heap_allocator(), "procedure group"); + xt = gb_string_make(temporary_allocator(), "procedure group"); } else { xt = type_to_string(x->type); } if (y->mode == Addressing_ProcGroup) { - yt = gb_string_make(heap_allocator(), "procedure group"); + yt = gb_string_make(temporary_allocator(), "procedure group"); } else { yt = type_to_string(y->type); } err_str = gb_string_make(temporary_allocator(), gb_bprintf("mismatched types '%s' and '%s'", xt, yt)); - gb_string_free(yt); - gb_string_free(xt); } if (err_str != nullptr) { @@ -3893,6 +3893,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { + TEMPORARY_ALLOCATOR_GUARD(); + isize count = t->Union.variants.count; ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count); isize valid_count = 0; @@ -4057,10 +4059,10 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open (c->state_flags & StateFlag_no_bounds_check) == 0) { BigInt i = exact_value_to_integer(operand.value).value_integer; if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) { + TEMPORARY_ALLOCATOR_GUARD(); String idx_str = big_int_to_string(temporary_allocator(), &i); - gbString expr_str = expr_to_string(operand.expr); + gbString expr_str = expr_to_string(operand.expr, temporary_allocator()); error(operand.expr, "Index '%s' cannot be a negative value, got %.*s", expr_str, LIT(idx_str)); - gb_string_free(expr_str); if (value) *value = 0; return false; } @@ -4120,10 +4122,10 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open } if (out_of_bounds) { + TEMPORARY_ALLOCATOR_GUARD(); String idx_str = big_int_to_string(temporary_allocator(), &i); - gbString expr_str = expr_to_string(operand.expr); + gbString expr_str = expr_to_string(operand.expr, temporary_allocator()); error(operand.expr, "Index '%s' is out of bounds range 0..<%lld, got %.*s", expr_str, max_count, LIT(idx_str)); - gb_string_free(expr_str); return false; } @@ -5446,6 +5448,8 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { bool show_error = show_error_mode == CallArgumentMode_ShowErrors; CallArgumentError err = CallArgumentError_None; + TEMPORARY_ALLOCATOR_GUARD(); + isize param_count = pt->param_count; bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); auto ordered_operands = array_make(temporary_allocator(), param_count); @@ -6358,6 +6362,8 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O ordered_operands = array_make(permanent_allocator(), param_count); array_copy(&ordered_operands, operands, 0); } else { + TEMPORARY_ALLOCATOR_GUARD(); + bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); // LEAK(bill) @@ -7146,6 +7152,8 @@ gb_internal bool attempt_implicit_selector_expr(CheckerContext *c, Operand *o, A return true; } if (is_type_union(th)) { + TEMPORARY_ALLOCATOR_GUARD(); + Type *union_type = base_type(th); auto operands = array_make(temporary_allocator(), 0, union_type->Union.variants.count); @@ -7329,6 +7337,8 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op uintptr key = hash_exact_value(operand.value); TypeAndToken *found = map_get(seen, key); if (found != nullptr) { + TEMPORARY_ALLOCATOR_GUARD(); + isize count = multi_map_count(seen, key); TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); @@ -7895,6 +7905,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (cl->elems[0]->kind == Ast_FieldValue) { + TEMPORARY_ALLOCATOR_GUARD(); + bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); for (Ast *elem : cl->elems) { @@ -8423,6 +8435,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * // NOTE(bill): Check for missing cases when `#partial literal` is not present if (cl->elems.count > 0 && !was_error && !is_partial) { + TEMPORARY_ALLOCATOR_GUARD(); + Type *et = base_type(index_type); GB_ASSERT(et->kind == Type_Enum); auto fields = et->Enum.fields; @@ -10469,6 +10483,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan gb_internal gbString expr_to_string(Ast *expression) { return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, false); } +gb_internal gbString expr_to_string(Ast *expression, gbAllocator allocator) { + return write_expr_to_string(gb_string_make(allocator, ""), expression, false); +} gb_internal gbString expr_to_string_shorthand(Ast *expression) { return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, true); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index b4dd4cd7d..a2a688b13 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1048,6 +1048,8 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags } if (!is_partial && is_type_enum(x.type)) { + TEMPORARY_ALLOCATOR_GUARD(); + Type *et = base_type(x.type); GB_ASSERT(is_type_enum(et)); auto fields = et->Enum.fields; @@ -1280,6 +1282,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ } if (!is_partial && is_type_union(type_deref(x.type))) { + TEMPORARY_ALLOCATOR_GUARD(); + Type *ut = base_type(type_deref(x.type)); GB_ASSERT(is_type_union(ut)); auto variants = ut->Union.variants; @@ -1523,6 +1527,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) return; } + TEMPORARY_ALLOCATOR_GUARD(); // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation @@ -1743,6 +1748,8 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case_ast_node(rs, RangeStmt, node); + TEMPORARY_ALLOCATOR_GUARD(); + u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; check_open_scope(ctx, node); diff --git a/src/common.cpp b/src/common.cpp index 988a992d0..6a6019482 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -716,6 +716,8 @@ gb_internal LoadedFileError load_file_32(char const *fullpath, LoadedFile *memor if (!copy_file_contents) { #if defined(GB_SYSTEM_WINDOWS) + TEMPORARY_ALLOCATOR_GUARD(); + isize w_len = 0; wchar_t *w_str = gb__alloc_utf8_to_ucs2(temporary_allocator(), fullpath, &w_len); if (w_str == nullptr) { @@ -817,6 +819,8 @@ gb_internal LoadedFileError load_file_32(char const *fullpath, LoadedFile *memor #define USE_DAMERAU_LEVENSHTEIN 1 gb_internal isize levenstein_distance_case_insensitive(String const &a, String const &b) { + TEMPORARY_ALLOCATOR_GUARD(); + isize w = b.len+1; isize h = a.len+1; isize *matrix = gb_alloc_array(temporary_allocator(), isize, w*h); diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 940e79f4b..c7382d6ff 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -48,6 +48,7 @@ struct Arena { MemoryBlock * curr_block; isize minimum_block_size; BlockingMutex mutex; + isize temp_count; }; enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll }; @@ -245,7 +246,66 @@ gb_internal void virtual_memory_dealloc(MemoryBlock *block_to_free) { } } +struct ArenaTemp { + Arena * arena; + MemoryBlock *block; + isize used; +}; + +ArenaTemp arena_temp_begin(Arena *arena) { + GB_ASSERT(arena); + ArenaTemp temp = {}; + temp.arena = arena; + temp.block = arena->curr_block; + if (arena->curr_block != nullptr) { + temp.used = arena->curr_block->used; + } + arena->temp_count += 1; + return temp; +} +void arena_temp_end(ArenaTemp const &temp) { + GB_ASSERT(temp.arena); + Arena *arena = temp.arena; + bool memory_block_found = false; + for (MemoryBlock *block = arena->curr_block; block != nullptr; block = block->prev) { + if (block == temp.block) { + memory_block_found = true; + break; + } + } + GB_ASSERT_MSG(memory_block_found, "memory block stored within ArenaTemp not owned by Arena"); + + while (arena->curr_block != temp.block) { + MemoryBlock *free_block = arena->curr_block; + if (free_block != nullptr) { + arena->curr_block = free_block->prev; + virtual_memory_dealloc(free_block); + } + } + + MemoryBlock *block = arena->curr_block; + if (block) { + GB_ASSERT_MSG(block->used >= temp.used, "out of order use of arena_temp_end"); + isize amount_to_zero = gb_min(block->used - temp.used, block->size - block->used); + gb_zero_size(block->base + temp.used, amount_to_zero); + block->used = temp.used; + } + + GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end"); + arena->temp_count -= 1; +} + + +struct ArenaTempGuard { + ArenaTempGuard(Arena *arena) { + this->temp = arena_temp_begin(arena); + } + ~ArenaTempGuard() { + arena_temp_end(this->temp); + } + ArenaTemp temp; +}; gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc); @@ -294,11 +354,13 @@ gb_internal gbAllocator permanent_allocator() { return arena_allocator(&permanent_arena); } +gb_global gb_thread_local Arena temporary_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE}; gb_internal gbAllocator temporary_allocator() { - return permanent_allocator(); + return arena_allocator(&temporary_arena); } - +#define TEMPORARY_ALLOCATOR_GUARD() ArenaTempGuard GB_DEFER_3(_arena_guard_){&temporary_arena} +#define PERMANENT_ALLOCATOR_GUARD() ArenaTempGuard GB_DEFER_3(_arena_guard_){&permanent_arena} -- cgit v1.2.3 From e97bf2ef358eef4499dfee0dc1533bf785d923f2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Jan 2023 15:38:23 +0000 Subject: Minimize contention on the deps for decls --- src/check_decl.cpp | 5 ++++- src/check_expr.cpp | 3 +++ src/checker.cpp | 7 +++++++ src/checker.hpp | 4 ++++ 4 files changed, 18 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f0059424e..e28861fc6 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1608,7 +1608,10 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de check_scope_usage(ctx->checker, ctx->scope); - add_deps_from_child_to_parent(decl); + if (decl->entity == nullptr) { + // Only care about nested procedure literals + add_deps_from_child_to_parent(decl); + } return true; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c1fa21dc4..52efd9a66 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9455,6 +9455,9 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast pl->decl = decl; check_procedure_later(ctx.checker, ctx.file, empty_token, decl, type, pl->body, pl->tags); + mutex_lock(&ctx.checker->nested_proc_lits_mutex); + array_add(&ctx.checker->nested_proc_lits, decl); + mutex_unlock(&ctx.checker->nested_proc_lits_mutex); } check_close_scope(&ctx); diff --git a/src/checker.cpp b/src/checker.cpp index 6d73348d1..7be3c71d1 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1256,6 +1256,7 @@ gb_internal void init_checker(Checker *c) { // NOTE(bill): 1 Mi elements should be enough on average array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20); + array_init(&c->nested_proc_lits, heap_allocator(), 0, 1<<20); mpsc_init(&c->global_untyped_queue, a); // , 1<<20); @@ -1267,6 +1268,7 @@ gb_internal void destroy_checker(Checker *c) { destroy_checker_context(&c->builtin_ctx); + array_free(&c->nested_proc_lits); array_free(&c->procs_to_check); mpsc_destroy(&c->global_untyped_queue); } @@ -5657,6 +5659,11 @@ gb_internal void check_walk_all_dependencies(DeclInfo *decl) { } gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { + mutex_lock(&c->nested_proc_lits_mutex); + for (DeclInfo *decl : c->nested_proc_lits) { + check_walk_all_dependencies(decl); + } + mutex_unlock(&c->nested_proc_lits_mutex); for (Entity *e : c->info.entities) { DeclInfo *decl = e->decl_info; check_walk_all_dependencies(decl); diff --git a/src/checker.hpp b/src/checker.hpp index 595618e1d..d461b1f6e 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -449,6 +449,10 @@ struct Checker { MPSCQueue procs_with_deferred_to_check; Array procs_to_check; + BlockingMutex nested_proc_lits_mutex; + Array nested_proc_lits; + + MPSCQueue global_untyped_queue; }; -- cgit v1.2.3 From 1ab90de4931f07ea61b1195de602f282a853568b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 14 Jan 2023 12:33:42 +0000 Subject: Minimize `StringMap` structure usage --- src/check_expr.cpp | 2 +- src/check_stmt.cpp | 4 +- src/checker.cpp | 10 +- src/common_memory.cpp | 7 +- src/docs.cpp | 4 +- src/docs_writer.cpp | 4 +- src/llvm_backend.cpp | 4 +- src/llvm_backend_general.cpp | 4 +- src/string_map.cpp | 226 ++++++++++++++++++++++++------------------- 9 files changed, 146 insertions(+), 119 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 52efd9a66..ff74a2547 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -234,7 +234,7 @@ gb_internal void check_did_you_mean_type(String const &name, Slice con gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") { ERROR_BLOCK(); - DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.entries.count, name); + DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.count, name); defer (did_you_mean_destroy(&d)); rw_mutex_shared_lock(&scope->mutex); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a2a688b13..21df1d0ea 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -626,7 +626,7 @@ gb_internal bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, defer (rw_mutex_unlock(&scope->mutex)); for (auto const &entry : scope->elements) { - String name = entry.key.string; + String name = entry.key; Entity *decl = entry.value; if (!is_entity_exported(decl)) continue; @@ -1323,7 +1323,7 @@ gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { ast_node(bs, BlockStmt, body); // NOTE(bill, 2020-09-23): This logic is prevent common erros with block statements // e.g. if cond { x := 123; } // this is an error - if (bs->scope != nullptr && bs->scope->elements.entries.count > 0) { + if (bs->scope != nullptr && bs->scope->elements.count > 0) { if (bs->scope->parent->node != nullptr) { switch (bs->scope->parent->node->kind) { case Ast_IfStmt: diff --git a/src/checker.cpp b/src/checker.cpp index 770e0d473..39a132060 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -765,7 +765,7 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { gb_printf_err("Fullpath: %.*s\n", LIT(path)); for (auto const &entry : info->packages) { - gb_printf_err("%.*s\n", LIT(entry.key.string)); + gb_printf_err("%.*s\n", LIT(entry.key)); } GB_ASSERT_MSG(found != nullptr, "Missing core package %.*s", LIT(name)); } @@ -3891,16 +3891,16 @@ gb_internal bool correct_single_type_alias(CheckerContext *c, Entity *e) { } gb_internal bool correct_type_alias_in_scope_backwards(CheckerContext *c, Scope *s) { - isize n = s->elements.entries.count; bool correction = false; - for (isize i = n-1; i >= 0; i--) { + u32 n = s->elements.count; + for (u32 i = n-1; i < n; i--) { correction |= correct_single_type_alias(c, s->elements.entries[i].value); } return correction; } gb_internal bool correct_type_alias_in_scope_forwards(CheckerContext *c, Scope *s) { - isize n = s->elements.entries.count; bool correction = false; + u32 n = s->elements.count; for (isize i = 0; i < n; i++) { correction |= correct_single_type_alias(c, s->elements.entries[i].value); } @@ -5539,7 +5539,7 @@ gb_internal void check_deferred_procedures(Checker *c) { gb_internal void check_unique_package_names(Checker *c) { StringMap pkgs = {}; // Key: package name - string_map_init(&pkgs, 2*c->info.packages.entries.count); + string_map_init(&pkgs, 2*c->info.packages.count); defer (string_map_destroy(&pkgs)); for (auto const &entry : c->info.packages) { diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 7d5d1f27a..22b91d8cb 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -509,15 +509,15 @@ gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) { template -gb_internal void resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count) { +gb_internal isize resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count) { GB_ASSERT(new_count >= 0); if (new_count == 0) { gb_free(a, *array); *array = nullptr; - return; + return 0; } if (new_count < old_count) { - return; + return old_count; } isize old_size = old_count * gb_size_of(T); isize new_size = new_count * gb_size_of(T); @@ -525,5 +525,6 @@ gb_internal void resize_array_raw(T **array, gbAllocator const &a, isize old_cou auto new_data = cast(T *)gb_resize_align(a, *array, old_size, new_size, alignment); GB_ASSERT(new_data != nullptr); *array = new_data; + return new_count; } diff --git a/src/docs.cpp b/src/docs.cpp index b1efa2b46..54bb0c7a2 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -210,7 +210,7 @@ gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) { } if (pkg->scope != nullptr) { - auto entities = array_make(heap_allocator(), 0, pkg->scope->elements.entries.count); + auto entities = array_make(heap_allocator(), 0, pkg->scope->elements.count); defer (array_free(&entities)); for (auto const &entry : pkg->scope->elements) { Entity *e = entry.value; @@ -348,7 +348,7 @@ gb_internal void generate_documentation(Checker *c) { odin_doc_write(info, output_file_path); } else { - auto pkgs = array_make(permanent_allocator(), 0, info->packages.entries.count); + auto pkgs = array_make(permanent_allocator(), 0, info->packages.count); for (auto const &entry : info->packages) { AstPackage *pkg = entry.value; if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 2aefe29eb..ea0946153 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -977,7 +977,7 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit defer (array_free(&entries)); for (auto const &element : pkg->scope->elements) { - String name = element.key.string; + String name = element.key; Entity *e = element.value; switch (e->kind) { case Entity_Invalid: @@ -1016,7 +1016,7 @@ gb_internal OdinDocArray odin_doc_add_pkg_entries(OdinDocWrit gb_internal void odin_doc_write_docs(OdinDocWriter *w) { - auto pkgs = array_make(heap_allocator(), 0, w->info->packages.entries.count); + auto pkgs = array_make(heap_allocator(), 0, w->info->packages.count); defer (array_free(&pkgs)); for (auto const &entry : w->info->packages) { AstPackage *pkg = entry.value; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 148511028..6cd224324 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1035,14 +1035,14 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) { LLVMSetLinkage(p->value, LLVMInternalLinkage); lb_begin_procedure_body(p); for (auto const &entry : m->objc_classes) { - String name = entry.key.string; + String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); lb_addr_store(p, entry.value, ptr); } for (auto const &entry : m->objc_selectors) { - String name = entry.key.string; + String name = entry.key; args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); lb_addr_store(p, entry.value, ptr); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index c4f6ccc91..e7c9a0985 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -130,8 +130,8 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { gen->info = &c->info; - map_init(&gen->modules, gen->info->packages.entries.count*2); - map_init(&gen->modules_through_ctx, gen->info->packages.entries.count*2); + map_init(&gen->modules, gen->info->packages.count*2); + map_init(&gen->modules_through_ctx, gen->info->packages.count*2); map_init(&gen->anonymous_proc_lits, 1024); diff --git a/src/string_map.cpp b/src/string_map.cpp index f7ecc4acc..3bd08d09f 100644 --- a/src/string_map.cpp +++ b/src/string_map.cpp @@ -1,3 +1,5 @@ +GB_STATIC_ASSERT(sizeof(MapIndex) == sizeof(u32)); + struct StringHashKey { u32 hash; String string; @@ -9,101 +11,108 @@ struct StringHashKey { return this->string; } }; +gb_internal gb_inline u32 string_hash(String const &s) { + return fnv32a(s.text, s.len) & 0x7fffffff; +} gb_internal gb_inline StringHashKey string_hash_string(String const &s) { StringHashKey hash_key = {}; - hash_key.hash = fnv32a(s.text, s.len); + hash_key.hash = string_hash(s); hash_key.string = s; return hash_key; } - -gb_internal gb_inline bool string_hash_key_equal(StringHashKey const &a, StringHashKey const &b) { - if (a.hash == b.hash) { - // NOTE(bill): If two string's hashes collide, compare the strings themselves - return a.string == b.string; - } - return false; -} - template struct StringMapEntry { - StringHashKey key; + String key; + u32 hash; MapIndex next; T value; }; template struct StringMap { - Slice hashes; - Array > entries; + MapIndex * hashes; + usize hashes_count; + StringMapEntry *entries; + u32 count; + u32 entries_capacity; }; -template gb_internal void string_map_init (StringMap *h, isize capacity = 16); -template gb_internal void string_map_destroy (StringMap *h); +template gb_internal void string_map_init (StringMap *h, usize capacity = 16); +template gb_internal void string_map_destroy (StringMap *h); -template gb_internal T * string_map_get (StringMap *h, char const *key); -template gb_internal T * string_map_get (StringMap *h, String const &key); -template gb_internal T * string_map_get (StringMap *h, StringHashKey const &key); +template gb_internal T * string_map_get (StringMap *h, char const *key); +template gb_internal T * string_map_get (StringMap *h, String const &key); +template gb_internal T * string_map_get (StringMap *h, StringHashKey const &key); -template gb_internal T & string_map_must_get (StringMap *h, char const *key); -template gb_internal T & string_map_must_get (StringMap *h, String const &key); -template gb_internal T & string_map_must_get (StringMap *h, StringHashKey const &key); +template gb_internal T & string_map_must_get(StringMap *h, char const *key); +template gb_internal T & string_map_must_get(StringMap *h, String const &key); +template gb_internal T & string_map_must_get(StringMap *h, StringHashKey const &key); -template gb_internal void string_map_set (StringMap *h, char const *key, T const &value); -template gb_internal void string_map_set (StringMap *h, String const &key, T const &value); -template gb_internal void string_map_set (StringMap *h, StringHashKey const &key, T const &value); +template gb_internal void string_map_set (StringMap *h, char const *key, T const &value); +template gb_internal void string_map_set (StringMap *h, String const &key, T const &value); +template gb_internal void string_map_set (StringMap *h, StringHashKey const &key, T const &value); -// template gb_internal void string_map_remove (StringMap *h, StringHashKey const &key); -template gb_internal void string_map_clear (StringMap *h); -template gb_internal void string_map_grow (StringMap *h); -template gb_internal void string_map_reserve (StringMap *h, isize new_count); +// template gb_internal void string_map_remove (StringMap *h, StringHashKey const &key); +template gb_internal void string_map_clear (StringMap *h); +template gb_internal void string_map_grow (StringMap *h); +template gb_internal void string_map_reserve (StringMap *h, usize new_count); gb_internal gbAllocator string_map_allocator(void) { return heap_allocator(); } template -gb_internal gb_inline void string_map_init(StringMap *h, isize capacity) { +gb_internal gb_inline void string_map_init(StringMap *h, usize capacity) { capacity = next_pow2_isize(capacity); - slice_init(&h->hashes, string_map_allocator(), capacity); - array_init(&h->entries, string_map_allocator(), 0, capacity); - for (isize i = 0; i < capacity; i++) { - h->hashes.data[i] = MAP_SENTINEL; - } + string_map_reserve(h, capacity); } template gb_internal gb_inline void string_map_destroy(StringMap *h) { - if (h->entries.allocator.proc == nullptr) { - h->entries.allocator = string_map_allocator(); - } - slice_free(&h->hashes, h->entries.allocator); - array_free(&h->entries); + gb_free(string_map_allocator(), h->hashes); + gb_free(string_map_allocator(), h->entries); } + +template +gb_internal void string_map__resize_hashes(StringMap *h, usize count) { + h->hashes_count = cast(u32)resize_array_raw(&h->hashes, string_map_allocator(), h->hashes_count, count); +} + + +template +gb_internal void string_map__reserve_entries(StringMap *h, usize capacity) { + h->entries_capacity = cast(u32)resize_array_raw(&h->entries, string_map_allocator(), h->entries_capacity, capacity); +} + + template -gb_internal MapIndex string_map__add_entry(StringMap *h, StringHashKey const &key) { +gb_internal MapIndex string_map__add_entry(StringMap *h, u32 hash, String const &key) { StringMapEntry e = {}; e.key = key; + e.hash = hash; e.next = MAP_SENTINEL; - array_add(&h->entries, e); - return cast(MapIndex)(h->entries.count-1); + string_map__reserve_entries(h, h->count+1); + h->entries[h->count++] = e; + return cast(MapIndex)(h->count-1); } template -gb_internal MapFindResult string_map__find(StringMap *h, StringHashKey const &key) { +gb_internal MapFindResult string_map__find(StringMap *h, u32 hash, String const &key) { MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes.count != 0) { - fr.hash_index = cast(MapIndex)(key.hash & (h->hashes.count-1)); - fr.entry_index = h->hashes.data[fr.hash_index]; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index != MAP_SENTINEL) { - if (string_hash_key_equal(h->entries.data[fr.entry_index].key, key)) { + auto *entry = &h->entries[fr.entry_index]; + if (entry->hash == hash && entry->key == key) { return fr; } fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.data[fr.entry_index].next; + fr.entry_index = entry->next; } } return fr; @@ -112,15 +121,16 @@ gb_internal MapFindResult string_map__find(StringMap *h, StringHashKey const template gb_internal MapFindResult string_map__find_from_entry(StringMap *h, StringMapEntry *e) { MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes.count != 0) { - fr.hash_index = cast(MapIndex)(e->key.hash & (h->hashes.count-1)); - fr.entry_index = h->hashes.data[fr.hash_index]; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(e->hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index != MAP_SENTINEL) { - if (&h->entries.data[fr.entry_index] == e) { + auto *entry = &h->entries[fr.entry_index]; + if (entry == e) { return fr; } fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries.data[fr.entry_index].next; + fr.entry_index = entry->next; } } return fr; @@ -128,24 +138,24 @@ gb_internal MapFindResult string_map__find_from_entry(StringMap *h, StringMap template gb_internal b32 string_map__full(StringMap *h) { - return 0.75f * h->hashes.count <= h->entries.count; + return 0.75f * h->hashes_count <= h->count; } template gb_inline void string_map_grow(StringMap *h) { - isize new_count = gb_max(h->hashes.count<<1, 16); + isize new_count = gb_max(h->hashes_count<<1, 16); string_map_reserve(h, new_count); } template gb_internal void string_map_reset_entries(StringMap *h) { - for (isize i = 0; i < h->hashes.count; i++) { - h->hashes.data[i] = MAP_SENTINEL; + for (u32 i = 0; i < h->hashes_count; i++) { + h->hashes[i] = MAP_SENTINEL; } - for (isize i = 0; i < h->entries.count; i++) { + for (isize i = 0; i < h->count; i++) { MapFindResult fr; - StringMapEntry *e = &h->entries.data[i]; + StringMapEntry *e = &h->entries[i]; e->next = MAP_SENTINEL; fr = string_map__find_from_entry(h, e); if (fr.entry_prev == MAP_SENTINEL) { @@ -157,27 +167,24 @@ gb_internal void string_map_reset_entries(StringMap *h) { } template -gb_internal void string_map_reserve(StringMap *h, isize cap) { - if (h->entries.allocator.proc == nullptr) { - h->entries.allocator = string_map_allocator(); - } - array_reserve(&h->entries, cap); - if (h->entries.count*2 < h->hashes.count) { +gb_internal void string_map_reserve(StringMap *h, usize cap) { + if (h->count*2 < h->hashes_count) { return; } - slice_resize(&h->hashes, h->entries.allocator, cap*2); + string_map__reserve_entries(h, cap); + string_map__resize_hashes(h, cap*2); string_map_reset_entries(h); } template -gb_internal T *string_map_get(StringMap *h, StringHashKey const &key) { +gb_internal T *string_map_get(StringMap *h, u32 hash, String const &key) { MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes.count != 0) { - fr.hash_index = cast(MapIndex)(key.hash & (h->hashes.count-1)); - fr.entry_index = h->hashes.data[fr.hash_index]; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index != MAP_SENTINEL) { - auto *entry = &h->entries.data[fr.entry_index]; - if (string_hash_key_equal(entry->key, key)) { + auto *entry = &h->entries[fr.entry_index]; + if (entry->hash == hash && entry->key == key) { return &entry->value; } fr.entry_prev = fr.entry_index; @@ -187,52 +194,65 @@ gb_internal T *string_map_get(StringMap *h, StringHashKey const &key) { return nullptr; } + +template +gb_internal gb_inline T *string_map_get(StringMap *h, StringHashKey const &key) { + return string_map_get(h, key.hash, key.string); +} + template gb_internal gb_inline T *string_map_get(StringMap *h, String const &key) { - return string_map_get(h, string_hash_string(key)); + return string_map_get(h, string_hash(key), key); } template gb_internal gb_inline T *string_map_get(StringMap *h, char const *key) { - return string_map_get(h, string_hash_string(make_string_c(key))); + String k = make_string_c(key); + return string_map_get(h, string_hash(k), k); } template -gb_internal T &string_map_must_get(StringMap *h, StringHashKey const &key) { - isize index = string_map__find(h, key).entry_index; +gb_internal T &string_map_must_get(StringMap *h, u32 hash, String const &key) { + isize index = string_map__find(h, hash, key).entry_index; GB_ASSERT(index != MAP_SENTINEL); - return h->entries.data[index].value; + return h->entries[index].value; +} + +template +gb_internal T &string_map_must_get(StringMap *h, StringHashKey const &key) { + return string_map_must_get(h, key.hash, key.string); } template gb_internal gb_inline T &string_map_must_get(StringMap *h, String const &key) { - return string_map_must_get(h, string_hash_string(key)); + return string_map_must_get(h, string_hash(key), key); } template gb_internal gb_inline T &string_map_must_get(StringMap *h, char const *key) { - return string_map_must_get(h, string_hash_string(make_string_c(key))); + String k = make_string_c(key); + return string_map_must_get(h, string_hash(k), k); } template -gb_internal void string_map_set(StringMap *h, StringHashKey const &key, T const &value) { +gb_internal void string_map_set(StringMap *h, u32 hash, String const &key, T const &value) { MapIndex index; MapFindResult fr; - if (h->hashes.count == 0) { + if (h->hashes_count == 0) { string_map_grow(h); } - fr = string_map__find(h, key); + fr = string_map__find(h, hash, key); if (fr.entry_index != MAP_SENTINEL) { index = fr.entry_index; } else { - index = string_map__add_entry(h, key); + index = string_map__add_entry(h, hash, key); if (fr.entry_prev != MAP_SENTINEL) { - h->entries.data[fr.entry_prev].next = index; + h->entries[fr.entry_prev].next = index; } else { - h->hashes.data[fr.hash_index] = index; + h->hashes[fr.hash_index] = index; } } - h->entries.data[index].value = value; + h->entries[index].value = value; if (string_map__full(h)) { string_map_grow(h); @@ -249,25 +269,31 @@ gb_internal gb_inline void string_map_set(StringMap *h, char const *key, T co string_map_set(h, string_hash_string(make_string_c(key)), value); } +template +gb_internal gb_inline void string_map_set(StringMap *h, StringHashKey const &key, T const &value) { + string_map_set(h, key.hash, key.string, value); +} + + // template // gb_internal void string_map__erase(StringMap *h, MapFindResult const &fr) { // MapFindResult last; // if (fr.entry_prev == MAP_SENTINEL) { -// h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next; +// h->hashes[fr.hash_index] = h->entries[fr.entry_index].next; // } else { -// h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next; +// h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; // } -// if (fr.entry_index == h->entries.count-1) { +// if (fr.entry_index == h->count-1) { // array_pop(&h->entries); // return; // } -// h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1]; -// last = string_map__find(h, h->entries.data[fr.entry_index].key); +// h->entries[fr.entry_index] = h->entries[h->count-1]; +// last = string_map__find(h, h->entries[fr.entry_index].key); // if (last.entry_prev != MAP_SENTINEL) { -// h->entries.data[last.entry_prev].next = fr.entry_index; +// h->entries[last.entry_prev].next = fr.entry_index; // } else { -// h->hashes.data[last.hash_index] = fr.entry_index; +// h->hashes[last.hash_index] = fr.entry_index; // } // } @@ -281,9 +307,9 @@ gb_internal gb_inline void string_map_set(StringMap *h, char const *key, T co template gb_internal gb_inline void string_map_clear(StringMap *h) { - array_clear(&h->entries); - for (isize i = 0; i < h->hashes.count; i++) { - h->hashes.data[i] = MAP_SENTINEL; + h->count = 0; + for (u32 i = 0; i < h->hashes_count; i++) { + h->hashes[i] = MAP_SENTINEL; } } @@ -291,20 +317,20 @@ gb_internal gb_inline void string_map_clear(StringMap *h) { template gb_internal StringMapEntry *begin(StringMap &m) noexcept { - return m.entries.data; + return m.entries; } template gb_internal StringMapEntry const *begin(StringMap const &m) noexcept { - return m.entries.data; + return m.entries; } template gb_internal StringMapEntry *end(StringMap &m) { - return m.entries.data + m.entries.count; + return m.entries + m.count; } template gb_internal StringMapEntry const *end(StringMap const &m) noexcept { - return m.entries.data + m.entries.count; + return m.entries + m.count; } \ No newline at end of file -- cgit v1.2.3 From d55248ab0ffcf796cfdc4961e813e69b2c71b723 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Jan 2023 11:45:15 +0000 Subject: Fix #2301 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ff74a2547..491114344 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7535,7 +7535,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n o->mode = Addressing_Value; o->expr = node; - if (type_hint != nullptr && is_type_untyped(o->type)) { + if (type_hint != nullptr && is_type_untyped(o->type) && !is_type_any(type_hint)) { if (check_cast_internal(c, &x, type_hint) && check_cast_internal(c, &y, type_hint)) { convert_to_typed(c, o, type_hint); -- cgit v1.2.3 From c819c350d62b2069adc36407a35cb12bd7066a25 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Jan 2023 11:58:14 +0000 Subject: Add error message for atomic intrinsics to prevent arbitrary types --- src/check_builtin.cpp | 34 ++++++++++++++++++++++++++++++++++ src/check_expr.cpp | 11 +++++++++++ 2 files changed, 45 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 290b1b8cd..5e132e764 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1188,6 +1188,15 @@ gb_internal bool is_valid_type_for_load(Type *type) { return false; } +gb_internal bool check_atomic_ptr_argument(Operand *operand, String const &builtin_name, Type *elem) { + if (!is_type_valid_atomic_type(elem)) { + error(operand->expr, "Only an integer, floating-point, boolean, or pointer can be used as an atomic for '%.*s'", LIT(builtin_name)); + return false; + } + return true; + +} + gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -4246,6 +4255,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (id == BuiltinProc_atomic_store && !check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); @@ -4262,6 +4274,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); @@ -4294,6 +4309,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (id == BuiltinProc_atomic_load && !check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } + operand->type = elem; operand->mode = Addressing_Value; break; @@ -4306,6 +4325,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } OdinAtomicMemoryOrder memory_order = {}; if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) { @@ -4337,6 +4359,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); @@ -4374,6 +4399,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); check_assignment(c, &x, elem, builtin_name); @@ -4412,6 +4440,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; Operand y = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); @@ -4439,6 +4470,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name)); return false; } + if (!check_atomic_ptr_argument(operand, builtin_name, elem)) { + return false; + } Operand x = {}; Operand y = {}; check_expr_with_type_hint(c, &x, ce->args[1], elem); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 491114344..431b36664 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4896,6 +4896,17 @@ gb_internal bool is_type_normal_pointer(Type *ptr, Type **elem) { return false; } +gb_internal bool is_type_valid_atomic_type(Type *elem) { + elem = core_type(elem); + if (elem->kind == Type_BitSet) { + elem = bit_set_to_int(elem); + } + if (elem->kind != Type_Basic) { + return false; + } + return (elem->Basic.flags & (BasicFlag_Boolean|BasicFlag_OrderedNumeric)) != 0; +} + gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) { switch (node->kind) { case_ast_node(i, Ident, node); -- cgit v1.2.3 From b55fa268bf156ff72551868d84f45b579e2025b2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Jan 2023 12:03:46 +0000 Subject: Fix #2267 by making it an error --- src/check_expr.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 431b36664..6c3e731f8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7323,8 +7323,10 @@ gb_internal void check_matrix_index_expr(CheckerContext *c, Operand *o, Ast *nod i64 column_index = 0; bool row_ok = check_index_value(c, t, false, ie->row_index, row_count, &row_index, nullptr); bool column_ok = check_index_value(c, t, false, ie->column_index, column_count, &column_index, nullptr); - - + if (is_const && (ie->row_index->tav.mode != Addressing_Constant || ie->column_index->tav.mode != Addressing_Constant)) { + error(o->expr, "Cannot index constant matrix with non-constant indices '%s'", expr_to_string(node)); + } + gb_unused(row_ok); gb_unused(column_ok); } -- cgit v1.2.3 From 2dca39b55716d84e760d3a33b9754c18d7f6f1cc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Jan 2023 12:06:03 +0000 Subject: Remove `auto_cast` procedure field flag Fixes #2285 --- core/runtime/core_builtin_soa.odin | 4 ++-- src/check_expr.cpp | 10 +--------- src/check_type.cpp | 17 +---------------- src/docs_writer.cpp | 1 - src/entity.cpp | 2 +- src/parser.cpp | 4 ---- src/parser.hpp | 4 ++-- 7 files changed, 7 insertions(+), 35 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/runtime/core_builtin_soa.odin b/core/runtime/core_builtin_soa.odin index a6b356642..2b7fd3681 100644 --- a/core/runtime/core_builtin_soa.odin +++ b/core/runtime/core_builtin_soa.odin @@ -150,14 +150,14 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context. } @builtin -make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { +make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { context.allocator = allocator resize_soa(&array, length, loc) return } @builtin -make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { +make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) { context.allocator = allocator if reserve_soa(&array, capacity, loc) { resize_soa(&array, length, loc) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6c3e731f8..608eb879b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5321,9 +5321,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { i64 s = 0; if (!check_is_assignable_to_with_score(c, &o, t, &s, param_is_variadic)) { bool ok = false; - if (e->flags & EntityFlag_AutoCast) { - ok = check_is_castable_to(c, &o, t); - } else if (e->flags & EntityFlag_AnyInt) { + if (e->flags & EntityFlag_AnyInt) { if (is_type_integer(t)) { ok = check_is_castable_to(c, &o, t); } @@ -5592,9 +5590,6 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { i64 s = 0; if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { bool ok = false; - if (e->flags & EntityFlag_AutoCast) { - ok = check_is_castable_to(c, o, e->type); - } if (ok) { s = assign_score_function(MAXIMUM_TYPE_DISTANCE); } else { @@ -10243,9 +10238,6 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan if (f->flags&FieldFlag_c_vararg) { str = gb_string_appendc(str, "#c_vararg "); } - if (f->flags&FieldFlag_auto_cast) { - str = gb_string_appendc(str, "auto_cast "); - } if (f->flags&FieldFlag_any_int) { str = gb_string_appendc(str, "#any_int "); } diff --git a/src/check_type.cpp b/src/check_type.cpp index 0bd9af15f..ad746514e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1619,10 +1619,6 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } } - if (p->flags&FieldFlag_auto_cast) { - error(name, "'auto_cast' can only be applied to variable fields"); - p->flags &= ~FieldFlag_auto_cast; - } if (p->flags&FieldFlag_const) { error(name, "'#const' can only be applied to variable fields"); p->flags &= ~FieldFlag_const; @@ -1681,11 +1677,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) { bool ok = true; - if (p->flags&FieldFlag_auto_cast) { - if (!check_is_castable_to(ctx, &op, type)) { - ok = false; - } - } else if (p->flags&FieldFlag_any_int) { + if (p->flags&FieldFlag_any_int) { if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { ok = false; } else if (!check_is_castable_to(ctx, &op, type)) { @@ -1731,10 +1723,6 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(name, "'#no_alias' can only be applied to non constant values"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } - if (p->flags&FieldFlag_auto_cast) { - error(name, "'auto_cast' can only be applied to variable fields"); - p->flags &= ~FieldFlag_auto_cast; - } if (p->flags&FieldFlag_any_int) { error(name, "'#any_int' can only be applied to variable fields"); p->flags &= ~FieldFlag_any_int; @@ -1765,9 +1753,6 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (p->flags&FieldFlag_no_alias) { param->flags |= EntityFlag_NoAlias; } - if (p->flags&FieldFlag_auto_cast) { - param->flags |= EntityFlag_AutoCast; - } if (p->flags&FieldFlag_any_int) { if (!is_type_integer(param->type) && !is_type_enum(param->type)) { gbString str = type_to_string(param->type); diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index cb7fa0e1e..814769f57 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -859,7 +859,6 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) if (e->flags & EntityFlag_Param) { if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; } if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; } - if (e->flags & EntityFlag_AutoCast) { flags |= OdinDocEntityFlag_Param_AutoCast; } if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; } if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; } if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; } diff --git a/src/entity.cpp b/src/entity.cpp index b92ba825f..4b0a6a3c8 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -61,7 +61,7 @@ enum EntityFlag : u64 { EntityFlag_ProcBodyChecked = 1ull<<21, EntityFlag_CVarArg = 1ull<<22, - EntityFlag_AutoCast = 1ull<<23, + EntityFlag_AnyInt = 1ull<<24, EntityFlag_Disabled = 1ull<<25, diff --git a/src/parser.cpp b/src/parser.cpp index c26ca3dcb..b364d01cf 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3524,7 +3524,6 @@ struct ParseFieldPrefixMapping { gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = { {str_lit("using"), Token_using, FieldFlag_using}, - {str_lit("auto_cast"), Token_auto_cast, FieldFlag_auto_cast}, {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias}, {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg}, {str_lit("const"), Token_Hash, FieldFlag_const}, @@ -3542,9 +3541,6 @@ gb_internal FieldFlag is_token_field_prefix(AstFile *f) { case Token_using: return FieldFlag_using; - case Token_auto_cast: - return FieldFlag_auto_cast; - case Token_Hash: advance_token(f); switch (f->curr_token.kind) { diff --git a/src/parser.hpp b/src/parser.hpp index 6782a9248..552e9bfb5 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -312,7 +312,7 @@ enum FieldFlag : u32 { FieldFlag_using = 1<<1, FieldFlag_no_alias = 1<<2, FieldFlag_c_vararg = 1<<3, - FieldFlag_auto_cast = 1<<4, + FieldFlag_const = 1<<5, FieldFlag_any_int = 1<<6, FieldFlag_subtype = 1<<7, @@ -327,7 +327,7 @@ enum FieldFlag : u32 { FieldFlag_Invalid = 1u<<31, // Parameter List Restrictions - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr, + FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr, FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, }; -- cgit v1.2.3 From 5d397804f7c02a2a71a10dd3af2f59a1bb3b4a10 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Jan 2023 13:22:37 +0000 Subject: Fix #2286 by printing an error correctly --- src/check_expr.cpp | 3 +++ src/check_type.cpp | 6 ++++++ src/llvm_backend_proc.cpp | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 608eb879b..b4b36a950 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4898,6 +4898,9 @@ gb_internal bool is_type_normal_pointer(Type *ptr, Type **elem) { gb_internal bool is_type_valid_atomic_type(Type *elem) { elem = core_type(elem); + if (is_type_internally_pointer_like(elem)) { + return true; + } if (elem->kind == Type_BitSet) { elem = bit_set_to_int(elem); } diff --git a/src/check_type.cpp b/src/check_type.cpp index ad746514e..ec661134b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1655,6 +1655,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } 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; + Entity *proc_entity = entity_from_expr(op.expr); + if ((proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure)) { + if (is_type_polymorphic(proc_entity->type, false)) { + error(op.expr, "Cannot determine complete type of partial polymorphic procedure"); + } + } } } if (is_poly_name) { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b95fc7da6..822bae84e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -68,7 +68,9 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); if (!entity->Procedure.is_foreign) { - GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s (was parapoly: %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true)); + if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { + GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); + } } String link_name = {}; -- cgit v1.2.3 From c45ca1bfcccb9b8f001a62a52c56eeeb5c73be88 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 28 Jan 2023 12:06:46 +0000 Subject: Correct `arena_temp_end` usage when no allocation ever happens for that arena --- core/mem/virtual/arena.odin | 36 +- core/runtime/print.odin | 67 +++ src/build_settings.cpp | 1 - src/check_expr.cpp | 4 +- src/check_stmt.cpp | 989 ++++++++++++++++++++++---------------------- src/common_memory.cpp | 60 +-- 6 files changed, 623 insertions(+), 534 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 411407c70..a5a345080 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -311,26 +311,28 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { arena := temp.arena sync.mutex_guard(&arena.mutex) - memory_block_found := false - for block := arena.curr_block; block != nil; block = block.prev { - if block == temp.block { - memory_block_found = true - break + if temp.block != nil { + memory_block_found := false + for block := arena.curr_block; block != nil; block = block.prev { + if block == temp.block { + memory_block_found = true + break + } + } + if !memory_block_found { + assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc) } - } - if !memory_block_found { - assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc) - } - for arena.curr_block != temp.block { - arena_growing_free_last_memory_block(arena) - } + for arena.curr_block != temp.block { + arena_growing_free_last_memory_block(arena) + } - if block := arena.curr_block; block != nil { - assert(block.used >= temp.used, "out of order use of arena_temp_end", loc) - amount_to_zero := min(block.used-temp.used, block.reserved-block.used) - mem.zero_slice(block.base[temp.used:][:amount_to_zero]) - block.used = temp.used + if block := arena.curr_block; block != nil { + assert(block.used >= temp.used, "out of order use of arena_temp_end", loc) + amount_to_zero := min(block.used-temp.used, block.reserved-block.used) + mem.zero_slice(block.base[temp.used:][:amount_to_zero]) + block.used = temp.used + } } assert(arena.temp_count > 0, "double-use of arena_temp_end", loc) diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 959dad3a9..1925587fd 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -2,6 +2,73 @@ package runtime _INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz" +when !ODIN_DISALLOW_RTTI { + print_any_single :: proc(arg: any) { + x := arg + if loc, ok := x.(Source_Code_Location); ok { + print_caller_location(loc) + return + } + x.id = typeid_base(x.id) + switch v in x { + case typeid: print_typeid(v) + case ^Type_Info: print_type(v) + + case string: print_string(v) + case cstring: print_string(string(v)) + case []byte: print_string(string(v)) + + case rune: print_rune(v) + + case u8: print_u64(u64(v)) + case u16: print_u64(u64(v)) + case u16le: print_u64(u64(v)) + case u16be: print_u64(u64(v)) + case u32: print_u64(u64(v)) + case u32le: print_u64(u64(v)) + case u32be: print_u64(u64(v)) + case u64: print_u64(u64(v)) + case u64le: print_u64(u64(v)) + case u64be: print_u64(u64(v)) + + case i8: print_i64(i64(v)) + case i16: print_i64(i64(v)) + case i16le: print_i64(i64(v)) + case i16be: print_i64(i64(v)) + case i32: print_i64(i64(v)) + case i32le: print_i64(i64(v)) + case i32be: print_i64(i64(v)) + case i64: print_i64(i64(v)) + case i64le: print_i64(i64(v)) + case i64be: print_i64(i64(v)) + + case int: print_int(v) + case uint: print_uint(v) + case uintptr: print_uintptr(v) + + case: + ti := type_info_of(x.id) + #partial switch v in ti.variant { + case Type_Info_Pointer: + print_uintptr((^uintptr)(x.data)^) + return + } + + print_string("") + } + } + println_any :: proc(args: ..any) { + loop: for arg, i in args { + if i != 0 { + print_string(" ") + } + print_any_single(arg) + } + print_string("\n") + } +} + + encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) { r := c diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 90e6512c5..904428602 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1050,7 +1050,6 @@ gb_internal bool has_asm_extension(String const &path) { // temporary gb_internal char *token_pos_to_string(TokenPos const &pos) { - TEMPORARY_ALLOCATOR_GUARD(); gbString s = gb_string_make_reserve(temporary_allocator(), 128); String file = get_file_path_string(pos.file_id); switch (build_context.ODIN_ERROR_POS_STYLE) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b4b36a950..df293e955 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2375,7 +2375,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok return; } - + TEMPORARY_ALLOCATOR_GUARD(); gbString err_str = nullptr; if (check_is_assignable_to(c, x, y->type) || @@ -2405,7 +2405,6 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok if (x->type == err_type && is_operand_nil(*x)) { err_type = y->type; } - TEMPORARY_ALLOCATOR_GUARD(); gbString type_string = type_to_string(err_type, temporary_allocator()); err_str = gb_string_make(temporary_allocator(), gb_bprintf("operator '%.*s' not defined for type '%s'", LIT(token_strings[op]), type_string)); @@ -2418,7 +2417,6 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok add_comparison_procedures_for_fields(c, comparison_type); } } else { - TEMPORARY_ALLOCATOR_GUARD(); gbString xt, yt; if (x->mode == Addressing_ProcGroup) { xt = gb_string_make(temporary_allocator(), "procedure group"); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 346d45f5b..8c21e29d4 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1415,6 +1415,503 @@ gb_internal bool check_expr_is_stack_variable(Ast *expr) { return false; } +gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { + ast_node(rs, RangeStmt, node); + + TEMPORARY_ALLOCATOR_GUARD(); + + u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; + + check_open_scope(ctx, node); + check_label(ctx, rs->label, node); + + auto vals = array_make(temporary_allocator(), 0, 2); + auto entities = array_make(temporary_allocator(), 0, 2); + bool is_map = false; + bool use_by_reference_for_value = false; + bool is_soa = false; + + Ast *expr = unparen_expr(rs->expr); + + isize max_val_count = 2; + if (is_ast_range(expr)) { + ast_node(ie, BinaryExpr, expr); + Operand x = {}; + Operand y = {}; + + bool ok = check_range(ctx, expr, &x, &y, nullptr); + if (!ok) { + goto skip_expr_range_stmt; + } + array_add(&vals, x.type); + array_add(&vals, t_int); + } else { + Operand operand = {Addressing_Invalid}; + check_expr_base(ctx, &operand, expr, nullptr); + error_operand_no_value(&operand); + + if (operand.mode == Addressing_Type) { + if (!is_type_enum(operand.type)) { + gbString t = type_to_string(operand.type); + error(operand.expr, "Cannot iterate over the type '%s'", t); + gb_string_free(t); + goto skip_expr_range_stmt; + } else { + array_add(&vals, operand.type); + array_add(&vals, t_int); + add_type_info_type(ctx, operand.type); + goto skip_expr_range_stmt; + } + } else if (operand.mode != Addressing_Invalid) { + bool is_ptr = is_type_pointer(operand.type); + Type *t = base_type(type_deref(operand.type)); + switch (t->kind) { + case Type_Basic: + if (is_type_string(t) && t->Basic.kind != Basic_cstring) { + array_add(&vals, t_rune); + array_add(&vals, t_int); + add_package_dependency(ctx, "runtime", "string_decode_rune"); + } + break; + + case Type_EnumeratedArray: + if (is_ptr) use_by_reference_for_value = true; + array_add(&vals, t->EnumeratedArray.elem); + array_add(&vals, t->EnumeratedArray.index); + break; + + case Type_Array: + if (is_ptr) use_by_reference_for_value = true; + array_add(&vals, t->Array.elem); + array_add(&vals, t_int); + break; + + case Type_DynamicArray: + if (is_ptr) use_by_reference_for_value = true; + array_add(&vals, t->DynamicArray.elem); + array_add(&vals, t_int); + break; + + case Type_Slice: + if (is_ptr) use_by_reference_for_value = true; + array_add(&vals, t->Slice.elem); + array_add(&vals, t_int); + break; + + case Type_Map: + if (is_ptr) use_by_reference_for_value = true; + is_map = true; + array_add(&vals, t->Map.key); + array_add(&vals, t->Map.value); + break; + + case Type_Tuple: + { + isize count = t->Tuple.variables.count; + if (count < 1 || count > 3) { + check_not_tuple(ctx, &operand); + error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n"); + break; + } + Type *cond_type = t->Tuple.variables[count-1]->type; + if (!is_type_boolean(cond_type)) { + gbString s = type_to_string(cond_type); + error(operand.expr, "The final type of %td-valued expression must be a boolean, got %s", count, s); + gb_string_free(s); + break; + } + + for (Entity *e : t->Tuple.variables) { + array_add(&vals, e->type); + } + + if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) { + gbString s = type_to_string(t); + error(operand.expr, "Expected a 3-valued expression on the rhs, got (%s)", s); + gb_string_free(s); + break; + } + + if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) { + gbString s = type_to_string(t); + error(operand.expr, "Expected at least a 2-valued expression on the rhs, got (%s)", s); + gb_string_free(s); + break; + } + + } + break; + + case Type_Struct: + if (t->Struct.soa_kind != StructSoa_None) { + is_soa = true; + if (is_ptr) use_by_reference_for_value = true; + array_add(&vals, t->Struct.soa_elem); + array_add(&vals, t_int); + } + break; + } + } + + if (vals.count == 0 || vals[0] == nullptr) { + gbString s = expr_to_string(operand.expr); + gbString t = type_to_string(operand.type); + defer (gb_string_free(s)); + defer (gb_string_free(t)); + + error(operand.expr, "Cannot iterate over '%s' of type '%s'", s, t); + + if (rs->vals.count == 1) { + Type *t = type_deref(operand.type); + if (is_type_map(t) || is_type_bit_set(t)) { + gbString v = expr_to_string(rs->vals[0]); + defer (gb_string_free(v)); + error_line("\tSuggestion: place parentheses around the expression\n"); + error_line("\t for (%s in %s) {\n", v, s); + } + } + } + } + + skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + + if (rs->vals.count > max_val_count) { + error(rs->vals[max_val_count], "Expected a maximum of %td identifier%s, got %td", max_val_count, max_val_count == 1 ? "" : "s", rs->vals.count); + } + + auto rhs = slice_from_array(vals); + auto lhs = slice_make(temporary_allocator(), rhs.count); + slice_copy(&lhs, rs->vals); + + isize addressable_index = cast(isize)is_map; + + for_array(i, rhs) { + if (lhs[i] == nullptr) { + continue; + } + Ast * name = lhs[i]; + Type *type = rhs[i]; + + Entity *entity = nullptr; + if (name->kind == Ast_Ident) { + Token token = name->Ident.token; + String str = token.string; + Entity *found = nullptr; + + if (!is_blank_ident(str)) { + found = scope_lookup_current(ctx->scope, str); + } + if (found == nullptr) { + entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); + entity->flags |= EntityFlag_ForValue; + entity->flags |= EntityFlag_Value; + entity->identifier = name; + if (i == addressable_index && use_by_reference_for_value) { + entity->flags &= ~EntityFlag_Value; + } + if (is_soa) { + if (i == 0) { + entity->flags |= EntityFlag_SoaPtrField; + } + } + + add_entity_definition(&ctx->checker->info, name, entity); + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %s", + LIT(str), token_pos_to_string(pos)); + entity = found; + } + } else { + error(name, "A variable declaration must be an identifier"); + } + + if (entity == nullptr) { + entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); + entity->identifier = name; // might not be an identifier + } + + array_add(&entities, entity); + + if (type == nullptr) { + entity->type = t_invalid; + entity->flags |= EntityFlag_Used; + } + } + + for (Entity *e : entities) { + DeclInfo *d = decl_info_of_entity(e); + GB_ASSERT(d == nullptr); + add_entity(ctx, ctx->scope, e->identifier, e); + d = make_decl_info(ctx->scope, ctx->decl); + add_entity_and_decl_info(ctx, e->identifier, e, d); + } + + check_stmt(ctx, rs->body, new_flags); + + check_close_scope(ctx); +} + +gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { + ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + // constant value declaration + // NOTE(bill): Check `_` declarations + for (Ast *name : vd->names) { + if (is_blank_ident(name)) { + Entity *e = name->Ident.entity; + DeclInfo *d = decl_info_of_entity(e); + if (d != nullptr) { + check_entity_decl(ctx, e, d, nullptr); + } + } + } + return; + } + Entity **entities = gb_alloc_array(permanent_allocator(), Entity *, vd->names.count); + isize entity_count = 0; + + isize new_name_count = 0; + for (Ast *name : vd->names) { + Entity *entity = nullptr; + if (name->kind != Ast_Ident) { + error(name, "A variable declaration must be an identifier"); + } else { + Token token = name->Ident.token; + String str = token.string; + Entity *found = nullptr; + // NOTE(bill): Ignore assignments to '_' + if (!is_blank_ident(str)) { + found = scope_lookup_current(ctx->scope, str); + new_name_count += 1; + } + if (found == nullptr) { + entity = alloc_entity_variable(ctx->scope, token, nullptr); + entity->identifier = name; + + Ast *fl = ctx->foreign_context.curr_library; + if (fl != nullptr) { + GB_ASSERT(fl->kind == Ast_Ident); + entity->Variable.is_foreign = true; + entity->Variable.foreign_library_ident = fl; + } + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %s", + LIT(str), token_pos_to_string(pos)); + entity = found; + } + } + if (entity == nullptr) { + entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); + } + entity->parent_proc_decl = ctx->curr_proc_decl; + entities[entity_count++] = entity; + if (name->kind == Ast_Ident) { + name->Ident.entity = entity; + } + } + + if (new_name_count == 0) { + begin_error_block(); + error(node, "No new declarations on the left hand side"); + bool all_underscore = true; + for (Ast *name : vd->names) { + if (name->kind == Ast_Ident) { + if (!is_blank_ident(name)) { + all_underscore = false; + break; + } + } else { + all_underscore = false; + break; + } + } + if (all_underscore) { + error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n"); + } + + end_error_block(); + } + + Type *init_type = nullptr; + if (vd->type != nullptr) { + init_type = check_type(ctx, vd->type); + if (init_type == nullptr) { + init_type = t_invalid; + } else if (is_type_polymorphic(base_type(init_type))) { + gbString str = type_to_string(init_type); + error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str); + gb_string_free(str); + init_type = t_invalid; + } + } + + + // TODO NOTE(bill): This technically checks things multple times + 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]; + GB_ASSERT(e != nullptr); + if (e->flags & EntityFlag_Visited) { + e->type = t_invalid; + continue; + } + e->flags |= EntityFlag_Visited; + + e->state = EntityState_InProgress; + if (e->type == nullptr) { + e->type = init_type; + e->state = EntityState_Resolved; + } + ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); + + if (ac.link_name.len > 0) { + e->Variable.link_name = ac.link_name; + } + + e->flags &= ~EntityFlag_Static; + if (ac.is_static) { + String name = e->token.string; + if (name == "_") { + error(e->token, "The 'static' attribute is not allowed to be applied to '_'"); + } else { + e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'static' variables cannot be declared within a defer statement"); + } + } + } + if (ac.thread_local_model != "") { + String name = e->token.string; + if (name == "_") { + error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'"); + } else { + e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'thread_local' variables cannot be declared within a defer statement"); + } + } + e->Variable.thread_local_model = ac.thread_local_model; + } + + if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { + error(e->token, "@(thread_local) is not supported for this target platform"); + } + + + if (ac.is_static && ac.thread_local_model != "") { + error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied"); + } + } + + check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration")); + check_arity_match(ctx, vd, false); + + for (isize i = 0; i < entity_count; i++) { + Entity *e = entities[i]; + + if (e->Variable.is_foreign) { + if (vd->values.count > 0) { + error(e->token, "A foreign variable declaration cannot have a default value"); + } + + String name = e->token.string; + if (e->Variable.link_name.len > 0) { + name = e->Variable.link_name; + } + + if (vd->values.count > 0) { + error(e->token, "A foreign variable declaration cannot have a default value"); + } + init_entity_foreign_library(ctx, e); + + auto *fp = &ctx->checker->info.foreigns; + StringHashKey key = string_hash_string(name); + Entity **found = string_map_get(fp, key); + if (found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + Type *this_type = base_type(e->type); + Type *other_type = base_type(f->type); + if (!are_types_identical(this_type, other_type)) { + error(e->token, + "Foreign entity '%.*s' previously declared elsewhere with a different type\n" + "\tat %s", + LIT(name), token_pos_to_string(pos)); + } + } else { + string_map_set(fp, key, e); + } + } else if (e->flags & EntityFlag_Static) { + if (vd->values.count > 0) { + if (entity_count != vd->values.count) { + error(e->token, "A static variable declaration with a default value must be constant"); + } else { + Ast *value = vd->values[i]; + if (value->tav.mode != Addressing_Constant) { + error(e->token, "A static variable declaration with a default value must be constant"); + } + } + } + } + add_entity(ctx, ctx->scope, e->identifier, e); + } + + if (vd->is_using != 0) { + Token token = ast_token(node); + if (vd->type != nullptr && entity_count > 1) { + error(token, "'using' can only be applied to one variable of the same type"); + // TODO(bill): Should a 'continue' happen here? + } + + for (isize entity_index = 0; entity_index < 1; entity_index++) { + Entity *e = entities[entity_index]; + if (e == nullptr) { + continue; + } + if (e->kind != Entity_Variable) { + continue; + } + String name = e->token.string; + Type *t = base_type(type_deref(e->type)); + + 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)) { + ERROR_BLOCK(); + + Scope *scope = t->Struct.scope; + GB_ASSERT(scope != nullptr); + for (auto const &entry : scope->elements) { + Entity *f = entry.value; + if (f->kind == Entity_Variable) { + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); + uvar->flags |= (e->flags & EntityFlag_Value); + Entity *prev = scope_insert(ctx->scope, uvar); + if (prev != nullptr) { + error(token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string)); + return; + } + } + } + + add_entity_use(ctx, nullptr, e); + } else { + // NOTE(bill): skip the rest to remove extra errors + error(token, "'using' can only be applied to variables of type struct or raw_union"); + return; + } + } + } +} + gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -1748,240 +2245,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case_ast_node(rs, RangeStmt, node); - TEMPORARY_ALLOCATOR_GUARD(); - - u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; - - check_open_scope(ctx, node); - check_label(ctx, rs->label, node); - - auto vals = array_make(temporary_allocator(), 0, 2); - auto entities = array_make(temporary_allocator(), 0, 2); - bool is_map = false; - bool use_by_reference_for_value = false; - bool is_soa = false; - - Ast *expr = unparen_expr(rs->expr); - - isize max_val_count = 2; - if (is_ast_range(expr)) { - ast_node(ie, BinaryExpr, expr); - Operand x = {}; - Operand y = {}; - - bool ok = check_range(ctx, expr, &x, &y, nullptr); - if (!ok) { - goto skip_expr_range_stmt; - } - array_add(&vals, x.type); - array_add(&vals, t_int); - } else { - Operand operand = {Addressing_Invalid}; - check_expr_base(ctx, &operand, expr, nullptr); - error_operand_no_value(&operand); - - if (operand.mode == Addressing_Type) { - if (!is_type_enum(operand.type)) { - gbString t = type_to_string(operand.type); - error(operand.expr, "Cannot iterate over the type '%s'", t); - gb_string_free(t); - goto skip_expr_range_stmt; - } else { - array_add(&vals, operand.type); - array_add(&vals, t_int); - add_type_info_type(ctx, operand.type); - goto skip_expr_range_stmt; - } - } else if (operand.mode != Addressing_Invalid) { - bool is_ptr = is_type_pointer(operand.type); - Type *t = base_type(type_deref(operand.type)); - switch (t->kind) { - case Type_Basic: - if (is_type_string(t) && t->Basic.kind != Basic_cstring) { - array_add(&vals, t_rune); - array_add(&vals, t_int); - add_package_dependency(ctx, "runtime", "string_decode_rune"); - } - break; - - case Type_EnumeratedArray: - if (is_ptr) use_by_reference_for_value = true; - array_add(&vals, t->EnumeratedArray.elem); - array_add(&vals, t->EnumeratedArray.index); - break; - - case Type_Array: - if (is_ptr) use_by_reference_for_value = true; - array_add(&vals, t->Array.elem); - array_add(&vals, t_int); - break; - - case Type_DynamicArray: - if (is_ptr) use_by_reference_for_value = true; - array_add(&vals, t->DynamicArray.elem); - array_add(&vals, t_int); - break; - - case Type_Slice: - if (is_ptr) use_by_reference_for_value = true; - array_add(&vals, t->Slice.elem); - array_add(&vals, t_int); - break; - - case Type_Map: - if (is_ptr) use_by_reference_for_value = true; - is_map = true; - array_add(&vals, t->Map.key); - array_add(&vals, t->Map.value); - break; - - case Type_Tuple: - { - isize count = t->Tuple.variables.count; - if (count < 1 || count > 3) { - check_not_tuple(ctx, &operand); - error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n"); - break; - } - Type *cond_type = t->Tuple.variables[count-1]->type; - if (!is_type_boolean(cond_type)) { - gbString s = type_to_string(cond_type); - error(operand.expr, "The final type of %td-valued expression must be a boolean, got %s", count, s); - gb_string_free(s); - break; - } - - for (Entity *e : t->Tuple.variables) { - array_add(&vals, e->type); - } - - if (rs->vals.count > 1 && rs->vals[1] != nullptr && count < 3) { - gbString s = type_to_string(t); - error(operand.expr, "Expected a 3-valued expression on the rhs, got (%s)", s); - gb_string_free(s); - break; - } - - if (rs->vals.count > 0 && rs->vals[0] != nullptr && count < 2) { - gbString s = type_to_string(t); - error(operand.expr, "Expected at least a 2-valued expression on the rhs, got (%s)", s); - gb_string_free(s); - break; - } - - } - break; - - case Type_Struct: - if (t->Struct.soa_kind != StructSoa_None) { - is_soa = true; - if (is_ptr) use_by_reference_for_value = true; - array_add(&vals, t->Struct.soa_elem); - array_add(&vals, t_int); - } - break; - } - } - - if (vals.count == 0 || vals[0] == nullptr) { - gbString s = expr_to_string(operand.expr); - gbString t = type_to_string(operand.type); - defer (gb_string_free(s)); - defer (gb_string_free(t)); - - error(operand.expr, "Cannot iterate over '%s' of type '%s'", s, t); - - if (rs->vals.count == 1) { - Type *t = type_deref(operand.type); - if (is_type_map(t) || is_type_bit_set(t)) { - gbString v = expr_to_string(rs->vals[0]); - defer (gb_string_free(v)); - error_line("\tSuggestion: place parentheses around the expression\n"); - error_line("\t for (%s in %s) {\n", v, s); - } - } - } - } - - skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. - - if (rs->vals.count > max_val_count) { - error(rs->vals[max_val_count], "Expected a maximum of %td identifier%s, got %td", max_val_count, max_val_count == 1 ? "" : "s", rs->vals.count); - } - - auto rhs = slice_from_array(vals); - auto lhs = slice_make(temporary_allocator(), rhs.count); - slice_copy(&lhs, rs->vals); - - isize addressable_index = cast(isize)is_map; - - for_array(i, rhs) { - if (lhs[i] == nullptr) { - continue; - } - Ast * name = lhs[i]; - Type *type = rhs[i]; - - Entity *entity = nullptr; - if (name->kind == Ast_Ident) { - Token token = name->Ident.token; - String str = token.string; - Entity *found = nullptr; - - if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); - } - if (found == nullptr) { - entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved); - entity->flags |= EntityFlag_ForValue; - entity->flags |= EntityFlag_Value; - entity->identifier = name; - if (i == addressable_index && use_by_reference_for_value) { - entity->flags &= ~EntityFlag_Value; - } - if (is_soa) { - if (i == 0) { - entity->flags |= EntityFlag_SoaPtrField; - } - } - - add_entity_definition(&ctx->checker->info, name, entity); - } else { - TokenPos pos = found->token.pos; - error(token, - "Redeclaration of '%.*s' in this scope\n" - "\tat %s", - LIT(str), token_pos_to_string(pos)); - entity = found; - } - } else { - error(name, "A variable declaration must be an identifier"); - } - - if (entity == nullptr) { - entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); - entity->identifier = name; // might not be an identifier - } - - array_add(&entities, entity); - - if (type == nullptr) { - entity->type = t_invalid; - entity->flags |= EntityFlag_Used; - } - } - - for (Entity *e : entities) { - DeclInfo *d = decl_info_of_entity(e); - GB_ASSERT(d == nullptr); - add_entity(ctx, ctx->scope, e->identifier, e); - d = make_decl_info(ctx->scope, ctx->decl); - add_entity_and_decl_info(ctx, e->identifier, e, d); - } - - check_stmt(ctx, rs->body, new_flags); - - check_close_scope(ctx); + check_range_stmt(ctx, node, mod_flags); case_end; case_ast_node(irs, UnrollRangeStmt, node); @@ -2134,262 +2398,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case_end; case_ast_node(vd, ValueDecl, node); - if (vd->is_mutable) { - Entity **entities = gb_alloc_array(permanent_allocator(), Entity *, vd->names.count); - isize entity_count = 0; - - isize new_name_count = 0; - for (Ast *name : vd->names) { - Entity *entity = nullptr; - if (name->kind != Ast_Ident) { - error(name, "A variable declaration must be an identifier"); - } else { - Token token = name->Ident.token; - String str = token.string; - Entity *found = nullptr; - // NOTE(bill): Ignore assignments to '_' - if (!is_blank_ident(str)) { - found = scope_lookup_current(ctx->scope, str); - new_name_count += 1; - } - if (found == nullptr) { - entity = alloc_entity_variable(ctx->scope, token, nullptr); - entity->identifier = name; - - Ast *fl = ctx->foreign_context.curr_library; - if (fl != nullptr) { - GB_ASSERT(fl->kind == Ast_Ident); - entity->Variable.is_foreign = true; - entity->Variable.foreign_library_ident = fl; - } - } else { - TokenPos pos = found->token.pos; - error(token, - "Redeclaration of '%.*s' in this scope\n" - "\tat %s", - LIT(str), token_pos_to_string(pos)); - entity = found; - } - } - if (entity == nullptr) { - entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); - } - entity->parent_proc_decl = ctx->curr_proc_decl; - entities[entity_count++] = entity; - if (name->kind == Ast_Ident) { - name->Ident.entity = entity; - } - } - - if (new_name_count == 0) { - begin_error_block(); - error(node, "No new declarations on the left hand side"); - bool all_underscore = true; - for (Ast *name : vd->names) { - if (name->kind == Ast_Ident) { - if (!is_blank_ident(name)) { - all_underscore = false; - break; - } - } else { - all_underscore = false; - break; - } - } - if (all_underscore) { - error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n"); - } - - end_error_block(); - } - - Type *init_type = nullptr; - if (vd->type != nullptr) { - init_type = check_type(ctx, vd->type); - if (init_type == nullptr) { - init_type = t_invalid; - } else if (is_type_polymorphic(base_type(init_type))) { - gbString str = type_to_string(init_type); - error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str); - gb_string_free(str); - init_type = t_invalid; - } - } - - - // TODO NOTE(bill): This technically checks things multple times - 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]; - GB_ASSERT(e != nullptr); - if (e->flags & EntityFlag_Visited) { - e->type = t_invalid; - continue; - } - e->flags |= EntityFlag_Visited; - - e->state = EntityState_InProgress; - if (e->type == nullptr) { - e->type = init_type; - e->state = EntityState_Resolved; - } - ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix); - - if (ac.link_name.len > 0) { - e->Variable.link_name = ac.link_name; - } - - e->flags &= ~EntityFlag_Static; - if (ac.is_static) { - String name = e->token.string; - if (name == "_") { - error(e->token, "The 'static' attribute is not allowed to be applied to '_'"); - } else { - e->flags |= EntityFlag_Static; - if (ctx->in_defer) { - error(e->token, "'static' variables cannot be declared within a defer statement"); - } - } - } - if (ac.thread_local_model != "") { - String name = e->token.string; - if (name == "_") { - error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'"); - } else { - e->flags |= EntityFlag_Static; - if (ctx->in_defer) { - error(e->token, "'thread_local' variables cannot be declared within a defer statement"); - } - } - e->Variable.thread_local_model = ac.thread_local_model; - } - - if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { - error(e->token, "@(thread_local) is not supported for this target platform"); - } - - - if (ac.is_static && ac.thread_local_model != "") { - error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied"); - } - } - - check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration")); - check_arity_match(ctx, vd, false); - - for (isize i = 0; i < entity_count; i++) { - Entity *e = entities[i]; - - if (e->Variable.is_foreign) { - if (vd->values.count > 0) { - error(e->token, "A foreign variable declaration cannot have a default value"); - } - - String name = e->token.string; - if (e->Variable.link_name.len > 0) { - name = e->Variable.link_name; - } - - if (vd->values.count > 0) { - error(e->token, "A foreign variable declaration cannot have a default value"); - } - init_entity_foreign_library(ctx, e); - - auto *fp = &ctx->checker->info.foreigns; - StringHashKey key = string_hash_string(name); - Entity **found = string_map_get(fp, key); - if (found) { - Entity *f = *found; - TokenPos pos = f->token.pos; - Type *this_type = base_type(e->type); - Type *other_type = base_type(f->type); - if (!are_types_identical(this_type, other_type)) { - error(e->token, - "Foreign entity '%.*s' previously declared elsewhere with a different type\n" - "\tat %s", - LIT(name), token_pos_to_string(pos)); - } - } else { - string_map_set(fp, key, e); - } - } else if (e->flags & EntityFlag_Static) { - if (vd->values.count > 0) { - if (entity_count != vd->values.count) { - error(e->token, "A static variable declaration with a default value must be constant"); - } else { - Ast *value = vd->values[i]; - if (value->tav.mode != Addressing_Constant) { - error(e->token, "A static variable declaration with a default value must be constant"); - } - } - } - } - add_entity(ctx, ctx->scope, e->identifier, e); - } - - if (vd->is_using != 0) { - Token token = ast_token(node); - if (vd->type != nullptr && entity_count > 1) { - error(token, "'using' can only be applied to one variable of the same type"); - // TODO(bill): Should a 'continue' happen here? - } - - for (isize entity_index = 0; entity_index < 1; entity_index++) { - Entity *e = entities[entity_index]; - if (e == nullptr) { - continue; - } - if (e->kind != Entity_Variable) { - continue; - } - String name = e->token.string; - Type *t = base_type(type_deref(e->type)); - - 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)) { - ERROR_BLOCK(); - - Scope *scope = t->Struct.scope; - GB_ASSERT(scope != nullptr); - for (auto const &entry : scope->elements) { - Entity *f = entry.value; - if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); - uvar->flags |= (e->flags & EntityFlag_Value); - Entity *prev = scope_insert(ctx->scope, uvar); - if (prev != nullptr) { - error(token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string)); - return; - } - } - } - - add_entity_use(ctx, nullptr, e); - } else { - // NOTE(bill): skip the rest to remove extra errors - error(token, "'using' can only be applied to variables of type struct or raw_union"); - return; - } - } - } - - } else { - // constant value declaration - // NOTE(bill): Check `_` declarations - for (Ast *name : vd->names) { - if (is_blank_ident(name)) { - Entity *e = name->Ident.entity; - DeclInfo *d = decl_info_of_entity(e); - if (d != nullptr) { - check_entity_decl(ctx, e, d, nullptr); - } - } - } - - } + check_value_decl_stmt(ctx, node, mod_flags); case_end; } } diff --git a/src/common_memory.cpp b/src/common_memory.cpp index d772eb795..ebdb0e4a7 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -271,35 +271,47 @@ void arena_temp_end(ArenaTemp const &temp) { Arena *arena = temp.arena; MUTEX_GUARD(&arena->mutex); - bool memory_block_found = false; - for (MemoryBlock *block = arena->curr_block; block != nullptr; block = block->prev) { - if (block == temp.block) { - memory_block_found = true; - break; + if (temp.block) { + bool memory_block_found = false; + for (MemoryBlock *block = arena->curr_block; block != nullptr; block = block->prev) { + if (block == temp.block) { + memory_block_found = true; + break; + } } - } - GB_ASSERT_MSG(memory_block_found, "memory block stored within ArenaTemp not owned by Arena"); + GB_ASSERT_MSG(memory_block_found, "memory block stored within ArenaTemp not owned by Arena"); - while (arena->curr_block != temp.block) { - MemoryBlock *free_block = arena->curr_block; - if (free_block != nullptr) { - arena->curr_block = free_block->prev; - virtual_memory_dealloc(free_block); + while (arena->curr_block != temp.block) { + MemoryBlock *free_block = arena->curr_block; + if (free_block != nullptr) { + arena->curr_block = free_block->prev; + virtual_memory_dealloc(free_block); + } } - } - MemoryBlock *block = arena->curr_block; - if (block) { - GB_ASSERT_MSG(block->used >= temp.used, "out of order use of arena_temp_end"); - isize amount_to_zero = gb_min(block->used - temp.used, block->size - block->used); - gb_zero_size(block->base + temp.used, amount_to_zero); - block->used = temp.used; + MemoryBlock *block = arena->curr_block; + if (block) { + GB_ASSERT_MSG(block->used >= temp.used, "out of order use of arena_temp_end"); + isize amount_to_zero = gb_min(block->used - temp.used, block->size - block->used); + gb_zero_size(block->base + temp.used, amount_to_zero); + block->used = temp.used; + } } GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end"); arena->temp_count -= 1; } +void arena_temp_ignore(ArenaTemp const &temp) { + GB_ASSERT(temp.arena); + Arena *arena = temp.arena; + MUTEX_GUARD(&arena->mutex); + + GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end"); + arena->temp_count -= 1; +} + + struct ArenaTempGuard { ArenaTempGuard(Arena *arena) { @@ -363,11 +375,13 @@ gb_internal gbAllocator temporary_allocator() { return arena_allocator(&temporary_arena); } -#define TEMPORARY_ALLOCATOR_GUARD() -#define PERMANENT_ALLOCATOR_GUARD() -// #define TEMPORARY_ALLOCATOR_GUARD() ArenaTempGuard GB_DEFER_3(_arena_guard_){&temporary_arena} -// #define PERMANENT_ALLOCATOR_GUARD() ArenaTempGuard GB_DEFER_3(_arena_guard_){&permanent_arena} +#define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena} + + +// #define TEMPORARY_ALLOCATOR_GUARD() +#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(&temporary_arena) +#define PERMANENT_ALLOCATOR_GUARD() -- cgit v1.2.3 From 8e8eb9e5cd4ba986d6125305e77cb82238bbcf0d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 30 Jan 2023 12:54:11 +0000 Subject: Improve ternary if expression type inference rues Allow for expression like this `x: union{f32} = f32(123) if cond else nil` --- src/check_expr.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index df293e955..27efbc9ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7518,16 +7518,25 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } - convert_to_typed(c, &x, y.type); + convert_to_typed(c, &x, type_hint ? type_hint : y.type); if (x.mode == Addressing_Invalid) { return kind; } - convert_to_typed(c, &y, x.type); + convert_to_typed(c, &y, type_hint ? type_hint : x.type); if (y.mode == Addressing_Invalid) { x.mode = Addressing_Invalid; return kind; } + // NOTE(bill, 2023-01-30): Allow for expression like this: + // x: union{f32} = f32(123) if cond else nil + if (type_hint && !ternary_compare_types(x.type, y.type)) { + if (check_is_assignable_to(c, &x, type_hint) && check_is_assignable_to(c, &y, type_hint)) { + check_cast(c, &x, type_hint); + check_cast(c, &y, type_hint); + } + } + if (!ternary_compare_types(x.type, y.type)) { gbString its = type_to_string(x.type); gbString ets = type_to_string(y.type); -- cgit v1.2.3 From f59846377d1877302abc108bab5ef1b0610e55ba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 30 Jan 2023 15:29:59 +0000 Subject: Improve ternary logic for untyped nil stuff --- src/check_expr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 27efbc9ae..47f453548 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7518,11 +7518,13 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } - convert_to_typed(c, &x, type_hint ? type_hint : y.type); + bool use_type_hint = type_hint != nullptr && (is_operand_nil(x) || is_operand_nil(y)); + + convert_to_typed(c, &x, use_type_hint ? type_hint : y.type); if (x.mode == Addressing_Invalid) { return kind; } - convert_to_typed(c, &y, type_hint ? type_hint : x.type); + convert_to_typed(c, &y, use_type_hint ? type_hint : x.type); if (y.mode == Addressing_Invalid) { x.mode = Addressing_Invalid; return kind; @@ -7530,7 +7532,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n // NOTE(bill, 2023-01-30): Allow for expression like this: // x: union{f32} = f32(123) if cond else nil - if (type_hint && !ternary_compare_types(x.type, y.type)) { + if (type_hint && !is_type_any(type_hint) && !ternary_compare_types(x.type, y.type)) { if (check_is_assignable_to(c, &x, type_hint) && check_is_assignable_to(c, &y, type_hint)) { check_cast(c, &x, type_hint); check_cast(c, &y, type_hint); -- cgit v1.2.3 From eb457d688d10e760ff581cf9bc33679a14d3a0b2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 Feb 2023 12:16:58 +0000 Subject: Make static map calls the default; add `-dynamic-map-calls` --- src/build_settings.cpp | 2 +- src/check_expr.cpp | 12 ++++++------ src/llvm_backend.cpp | 42 +++++++++++++++++++++--------------------- src/main.cpp | 13 +++++++++---- 4 files changed, 37 insertions(+), 32 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d18ca5603..c36df5527 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -306,7 +306,7 @@ struct BuildContext { bool disallow_rtti; - bool use_static_map_calls; + bool dynamic_map_calls; RelocMode reloc_mode; bool disable_red_zone; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 47f453548..58372f7a3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -281,11 +281,11 @@ gb_internal void error_operand_no_value(Operand *o) { } gb_internal void add_map_get_dependencies(CheckerContext *c) { - if (build_context.use_static_map_calls) { + if (build_context.dynamic_map_calls) { + add_package_dependency(c, "runtime", "__dynamic_map_get"); + } else { add_package_dependency(c, "runtime", "map_desired_position"); add_package_dependency(c, "runtime", "map_probe_distance"); - } else { - add_package_dependency(c, "runtime", "__dynamic_map_get"); } } @@ -297,11 +297,11 @@ gb_internal void add_map_set_dependencies(CheckerContext *c) { t_map_set_proc = alloc_type_proc_from_types(map_set_args, gb_count_of(map_set_args), t_rawptr, false, ProcCC_Odin); } - if (build_context.use_static_map_calls) { + if (build_context.dynamic_map_calls) { + add_package_dependency(c, "runtime", "__dynamic_map_set"); + } else { add_package_dependency(c, "runtime", "__dynamic_map_check_grow"); add_package_dependency(c, "runtime", "map_insert_hash_dynamic"); - } else { - add_package_dependency(c, "runtime", "__dynamic_map_set"); } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index c718aa519..85975cb12 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -457,7 +457,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { - GB_ASSERT(build_context.use_static_map_calls); + GB_ASSERT(!build_context.dynamic_map_calls); type = base_type(type); GB_ASSERT(type->kind == Type_Map); @@ -610,7 +610,7 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { // } gb_internal lbValue lb_map_set_proc_for_type(lbModule *m, Type *type) { - GB_ASSERT(build_context.use_static_map_calls); + GB_ASSERT(!build_context.dynamic_map_calls); type = base_type(type); GB_ASSERT(type->kind == Type_Map); @@ -907,7 +907,15 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons lbValue key_ptr = {}; lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr); - if (build_context.use_static_map_calls) { + if (build_context.dynamic_map_calls) { + auto args = array_make(permanent_allocator(), 4); + args[0] = lb_emit_transmute(p, map_ptr, t_raw_map_ptr); + args[1] = lb_gen_map_info_ptr(p->module, map_type); + args[2] = hash; + args[3] = key_ptr; + + ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + } else { lbValue map_get_proc = lb_map_get_proc_for_type(p->module, map_type); auto args = array_make(permanent_allocator(), 3); @@ -916,14 +924,6 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons args[2] = key_ptr; ptr = lb_emit_call(p, map_get_proc, args); - } else { - auto args = array_make(permanent_allocator(), 4); - args[0] = lb_emit_transmute(p, map_ptr, t_raw_map_ptr); - args[1] = lb_gen_map_info_ptr(p->module, map_type); - args[2] = hash; - args[3] = key_ptr; - - ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); } return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); } @@ -939,7 +939,16 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); lbValue value_ptr = lb_address_from_load_or_generate_local(p, v); - if (build_context.use_static_map_calls) { + if (build_context.dynamic_map_calls) { + auto args = array_make(permanent_allocator(), 6); + args[0] = lb_emit_conv(p, map_ptr, t_raw_map_ptr); + args[1] = lb_gen_map_info_ptr(p->module, map_type); + args[2] = hash; + args[3] = lb_emit_conv(p, key_ptr, t_rawptr); + args[4] = lb_emit_conv(p, value_ptr, t_rawptr); + args[5] = lb_emit_source_code_location_as_global(p, node); + lb_emit_runtime_call(p, "__dynamic_map_set", args); + } else { lbValue map_set_proc = lb_map_set_proc_for_type(p->module, map_type); auto args = array_make(permanent_allocator(), 5); @@ -950,15 +959,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ args[4] = lb_emit_source_code_location_as_global(p, node); lb_emit_call(p, map_set_proc, args); - } else { - auto args = array_make(permanent_allocator(), 6); - args[0] = lb_emit_conv(p, map_ptr, t_raw_map_ptr); - args[1] = lb_gen_map_info_ptr(p->module, map_type); - args[2] = hash; - args[3] = lb_emit_conv(p, key_ptr, t_rawptr); - args[4] = lb_emit_conv(p, value_ptr, t_rawptr); - args[5] = lb_emit_source_code_location_as_global(p, node); - lb_emit_runtime_call(p, "__dynamic_map_set", args); } } diff --git a/src/main.cpp b/src/main.cpp index 6b9e05a86..9c44af335 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -647,7 +647,7 @@ enum BuildFlagKind { BuildFlag_StrictStyleInitOnly, BuildFlag_ForeignErrorProcedures, BuildFlag_DisallowRTTI, - BuildFlag_UseStaticMapCalls, + BuildFlag_DynamicMapCalls, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -824,7 +824,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_UseStaticMapCalls, str_lit("use-static-map-calls"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc); @@ -1407,8 +1407,8 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_DisallowRTTI: build_context.disallow_rtti = true; break; - case BuildFlag_UseStaticMapCalls: - build_context.use_static_map_calls = true; + case BuildFlag_DynamicMapCalls: + build_context.dynamic_map_calls = true; break; case BuildFlag_DefaultToNilAllocator: build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true; @@ -2130,6 +2130,11 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-disable-red-zone"); print_usage_line(2, "Disable red zone on a supported freestanding target"); + print_usage_line(0, ""); + + print_usage_line(1, "-dynamic-map-calls"); + print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution"); + print_usage_line(0, ""); } if (check) { -- cgit v1.2.3 From 5eeb4366263117147710e2867d1ff5d772cdc7ac Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 Feb 2023 12:43:21 +0000 Subject: Temporarily make all `map` get calls dynamic --- src/check_expr.cpp | 6 +++--- src/llvm_backend.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 58372f7a3..b66862ccd 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -281,12 +281,12 @@ gb_internal void error_operand_no_value(Operand *o) { } gb_internal void add_map_get_dependencies(CheckerContext *c) { - if (build_context.dynamic_map_calls) { + // if (build_context.dynamic_map_calls) { add_package_dependency(c, "runtime", "__dynamic_map_get"); - } else { + // } else { add_package_dependency(c, "runtime", "map_desired_position"); add_package_dependency(c, "runtime", "map_probe_distance"); - } + // } } gb_internal void add_map_set_dependencies(CheckerContext *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 85975cb12..3cc5efd52 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -907,7 +907,7 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons lbValue key_ptr = {}; lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr); - if (build_context.dynamic_map_calls) { + if (true || build_context.dynamic_map_calls) { auto args = array_make(permanent_allocator(), 4); args[0] = lb_emit_transmute(p, map_ptr, t_raw_map_ptr); args[1] = lb_gen_map_info_ptr(p->module, map_type); -- cgit v1.2.3 From 60e73d91f6e3661b83bff0cb51ad901f1776adb3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 Feb 2023 13:42:23 +0000 Subject: Remove internal `readonly` attribute --- src/check_expr.cpp | 6 +++--- src/llvm_backend.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b66862ccd..58372f7a3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -281,12 +281,12 @@ gb_internal void error_operand_no_value(Operand *o) { } gb_internal void add_map_get_dependencies(CheckerContext *c) { - // if (build_context.dynamic_map_calls) { + if (build_context.dynamic_map_calls) { add_package_dependency(c, "runtime", "__dynamic_map_get"); - // } else { + } else { add_package_dependency(c, "runtime", "map_desired_position"); add_package_dependency(c, "runtime", "map_probe_distance"); - // } + } } gb_internal void add_map_set_dependencies(CheckerContext *c) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 3cc5efd52..f131fe3e3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -495,11 +495,11 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { lb_add_proc_attribute_at_index(p, 1+0, "nonnull"); lb_add_proc_attribute_at_index(p, 1+0, "noalias"); - lb_add_proc_attribute_at_index(p, 1+0, "readonly"); + // lb_add_proc_attribute_at_index(p, 1+0, "readonly"); lb_add_proc_attribute_at_index(p, 1+2, "nonnull"); lb_add_proc_attribute_at_index(p, 1+2, "noalias"); - lb_add_proc_attribute_at_index(p, 1+2, "readonly"); + // lb_add_proc_attribute_at_index(p, 1+2, "readonly"); lbBlock *loop_block = lb_create_block(p, "loop"); lbBlock *hash_block = lb_create_block(p, "hash"); @@ -907,7 +907,7 @@ gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue cons lbValue key_ptr = {}; lbValue hash = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr); - if (true || build_context.dynamic_map_calls) { + if (build_context.dynamic_map_calls) { auto args = array_make(permanent_allocator(), 4); args[0] = lb_emit_transmute(p, map_ptr, t_raw_map_ptr); args[1] = lb_gen_map_info_ptr(p->module, map_type); -- cgit v1.2.3 From e6239ca3c26ecf5db53353a0495d8745ea612209 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 10 Feb 2023 13:17:04 +0000 Subject: Warn on 'expand_to_tuple' has been replaced with 'expand_values' --- src/check_expr.cpp | 4 ++++ src/checker.cpp | 7 +++++++ 2 files changed, 11 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 58372f7a3..80a27bd79 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6744,6 +6744,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (operand->mode == Addressing_Builtin) { i32 id = operand->builtin_id; + Entity *e = entity_of_node(operand->expr); + if (e != nullptr && e->token.string == "expand_to_tuple") { + warning(operand->expr, "'expand_to_tuple' has been replaced with 'expand_values'"); + } if (!check_builtin_procedure(c, operand, call, id, type_hint)) { operand->mode = Addressing_Invalid; operand->type = t_invalid; diff --git a/src/checker.cpp b/src/checker.cpp index 303a2449e..bcaa11b8b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1070,6 +1070,13 @@ gb_internal void init_universal(void) { } } } + { + BuiltinProcId id = BuiltinProc_expand_values; + String name = str_lit("expand_to_tuple"); + Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid); + entity->Builtin.id = id; + add_global_entity(entity, builtin_pkg->scope); + } bool defined_values_double_declaration = false; for (auto const &entry : bc->defined_values) { -- cgit v1.2.3 From 8a2a70a3c2a7ac14687d100325e12b8d3d02256e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 17 Feb 2023 13:00:37 +0000 Subject: Fix overriding procedure information for literals --- src/check_decl.cpp | 17 +++++++++++++++++ src/check_expr.cpp | 4 +++- src/check_type.cpp | 12 ++++++++---- src/checker.cpp | 4 ++-- src/checker.hpp | 4 ++-- src/llvm_backend_const.cpp | 1 - src/llvm_backend_expr.cpp | 2 +- 7 files changed, 33 insertions(+), 11 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 63e6514e0..dc929cbca 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1480,6 +1480,23 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; + if (ctx->proc_name == "sort") { + if (type->Proc.param_count > 0) { + TypeTuple *params = &type->Proc.params->Tuple; + for (Entity *e : params->variables) { + if (e->kind == Entity_Constant) { + Ast *ident = e->identifier.load(); + if (ident) { + add_entity(ctx, e->scope, ident, e); + ident->tav.mode = Addressing_Constant; + ident->tav.value = e->Constant.value; + ident->tav.type = e->type; + } + } + } + } + } + if (ctx->pkg->name != "runtime") { switch (type->Proc.calling_convention) { case ProcCC_None: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 58372f7a3..93db559f8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5418,7 +5418,9 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; - add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + if (!are_types_identical(final_proc_type, ce->proc->tav.type)) { + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + } } return err; diff --git a/src/check_type.cpp b/src/check_type.cpp index ec661134b..24ca8628e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1666,17 +1666,21 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (is_poly_name) { bool valid = false; if (is_type_proc(op.type)) { - Entity *proc_entity = entity_from_expr(op.expr); - valid = (proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure); - if (valid) { + Ast *expr = unparen_expr(op.expr); + Entity *proc_entity = entity_from_expr(expr); + if (proc_entity) { poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr); + valid = true; + } else if (expr->kind == Ast_ProcLit) { + poly_const = exact_value_procedure(expr); + valid = true; } } if (!valid) { if (op.mode == Addressing_Constant) { poly_const = op.value; } else { - error(op.expr, "Expected a constant value for this polymorphic name parameter"); + error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); success = false; } } diff --git a/src/checker.cpp b/src/checker.cpp index 5163fe675..94bbb32e6 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1416,7 +1416,7 @@ gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_f } -gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; } @@ -1433,7 +1433,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; } diff --git a/src/checker.hpp b/src/checker.hpp index 4c3b8725a..b82612813 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -485,9 +485,9 @@ gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **s gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); -gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value); +gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); gb_internal void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e); gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index ee564bbf1..fc1598024 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -411,7 +411,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Ast *expr = unparen_expr(value.value_procedure); if (expr->kind == Ast_ProcLit) { res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } else { Entity *e = entity_from_expr(expr); res = lb_find_procedure_value_from_entity(m, e); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7cf8d56db..480831a68 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3138,7 +3138,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { Entity *e = entity_from_expr(expr); e = strip_entity_wrapping(e); - GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr)); + GB_ASSERT_MSG(e != nullptr, "%s in %.*s %p", expr_to_string(expr), LIT(p->name), expr); if (e->kind == Entity_Builtin) { Token token = ast_token(expr); GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" -- cgit v1.2.3 From 20eacc4a8493f0d0088ceebbcc1490207c48b5ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 19 Feb 2023 12:10:28 +0000 Subject: Fix issue that conflicts with constant parapoly procedures and `deferred_*` procedures --- src/check_decl.cpp | 13 ------------- src/check_expr.cpp | 5 ++--- 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1adb1e2ed..63e6514e0 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1532,19 +1532,6 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de break; } } - - // Add constant data to the identifier directly - for (Entity *e : params->variables) { - if (e->kind == Entity_Constant) { - Ast *ident = e->identifier.load(); - if (ident) { - add_entity(ctx, e->scope, ident, e); - ident->tav.mode = Addressing_Constant; - ident->tav.value = e->Constant.value; - ident->tav.type = e->type; - } - } - } } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 93db559f8..356f0aaa3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5418,9 +5418,8 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; - if (!are_types_identical(final_proc_type, ce->proc->tav.type)) { - add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); - } + + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); } return err; -- cgit v1.2.3 From c386c72d10540a4a9af89755df7aa3a35a079b64 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 19 Feb 2023 12:11:57 +0000 Subject: Check for procedure literals in `$` parameters --- src/check_expr.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 356f0aaa3..2ed77535c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5419,7 +5419,17 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; - add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + + Ast *proc_lit = nullptr; + if (ce->proc->tav.value.kind == ExactValue_Procedure) { + Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure); + if (vp && vp->kind == Ast_ProcLit) { + proc_lit = vp; + } + } + if (proc_lit == nullptr) { + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + } } return err; -- cgit v1.2.3 From a2f02b8b3218dc83a2a2783ceb79cc57abacc7bd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 21 Feb 2023 16:31:22 +0000 Subject: Fix bug with for in statements and pointer intervals --- src/check_expr.cpp | 20 ++++++++++++++------ src/check_stmt.cpp | 4 ++-- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2ed77535c..8a3bb2c1b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7040,7 +7040,7 @@ gb_internal bool ternary_compare_types(Type *x, Type *y) { } -gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { +gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { if (!is_ast_range(node)) { return false; } @@ -7089,9 +7089,17 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand * } Type *type = x->type; - if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { - error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - return false; + + if (is_for_loop) { + if (!is_type_integer(type) && !is_type_float(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical types are allowed within interval expressions"); + return false; + } + } else { + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + return false; + } } if (x->mode == Addressing_Constant && @@ -8104,7 +8112,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Operand x = {}; Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr); + bool ok = check_range(c, fv->field, false, &x, &y, nullptr); if (!ok) { continue; } @@ -8320,7 +8328,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Operand x = {}; Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type); + bool ok = check_range(c, fv->field, false, &x, &y, nullptr, index_type); if (!ok) { continue; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 3039995b9..f300f45c7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -725,7 +725,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod Operand x = {}; Operand y = {}; - bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth); + bool ok = check_range(ctx, expr, true, &x, &y, &inline_for_depth); if (!ok) { goto skip_expr; } @@ -1439,7 +1439,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) Operand x = {}; Operand y = {}; - bool ok = check_range(ctx, expr, &x, &y, nullptr); + bool ok = check_range(ctx, expr, true, &x, &y, nullptr); if (!ok) { goto skip_expr_range_stmt; } -- cgit v1.2.3 From b6a5c5f5d2a466e867f59c463987ba8ee28664a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 21 Feb 2023 17:24:22 +0000 Subject: Improve some error messages when casting a constant value which needs to be truncated/rounded --- src/check_expr.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8a3bb2c1b..c4a29b04a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2915,17 +2915,32 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { bool can_convert = check_cast_internal(c, x, type); if (!can_convert) { - gbString expr_str = expr_to_string(x->expr); - gbString to_type = type_to_string(type); - gbString from_type = type_to_string(x->type); - error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type); - gb_string_free(from_type); - gb_string_free(to_type); - gb_string_free(expr_str); + TEMPORARY_ALLOCATOR_GUARD(); + gbString expr_str = expr_to_string(x->expr, temporary_allocator()); + gbString to_type = type_to_string(type, temporary_allocator()); + gbString from_type = type_to_string(x->type, temporary_allocator()); + x->mode = Addressing_Invalid; + + begin_error_block(); + error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type); + if (is_const_expr) { + gbString val_str = exact_value_to_string(x->value); + if (is_type_float(x->type) && is_type_integer(type)) { + error_line("\t%s cannot be expressed without truncation/rounding as the type '%s'\n", val_str, to_type); + + // NOTE(bill): keep the mode and modify the type to minimize errors further on + x->mode = Addressing_Constant; + x->type = type; + } else { + error_line("\t%s cannot be expressed as the type '%s'\n", val_str, to_type); + } + gb_string_free(val_str); + } check_cast_error_suggestion(c, x, type); - x->mode = Addressing_Invalid; + end_error_block(); + return; } -- cgit v1.2.3 From 59a601f2cf1f7575662e4e7f1c3cabd079280d0a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 21 Feb 2023 23:08:02 +0000 Subject: Improve error messages when trying to access a non-existent field on a type --- src/check_expr.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c4a29b04a..30e2c9ad8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4745,20 +4745,29 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); - error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); - - if (operand->type != nullptr && selector->kind == Ast_Ident) { - String const &name = selector->Ident.token.string; - Type *bt = base_type(operand->type); - if (operand->type->kind == Type_Named && - operand->type->Named.type_name && - operand->type->Named.type_name->kind == Entity_TypeName && - operand->type->Named.type_name->TypeName.objc_metadata) { - check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type); - } else if (bt->kind == Type_Struct) { - check_did_you_mean_type(name, bt->Struct.fields); - } else if (bt->kind == Type_Enum) { - check_did_you_mean_type(name, bt->Enum.fields); + + if (operand->mode == Addressing_Type) { + if (is_type_polymorphic(operand->type, true)) { + error(op_expr, "Type '%s' has no field nor polymorphic parameter '%s'", op_str, sel_str); + } else { + error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str); + } + } else { + error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); + + if (operand->type != nullptr && selector->kind == Ast_Ident) { + String const &name = selector->Ident.token.string; + Type *bt = base_type(operand->type); + if (operand->type->kind == Type_Named && + operand->type->Named.type_name && + operand->type->Named.type_name->kind == Entity_TypeName && + operand->type->Named.type_name->TypeName.objc_metadata) { + check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type); + } else if (bt->kind == Type_Struct) { + check_did_you_mean_type(name, bt->Struct.fields); + } else if (bt->kind == Type_Enum) { + check_did_you_mean_type(name, bt->Enum.fields); + } } } -- cgit v1.2.3 From b9f7b2fdfaa41e9b4e48362d3bc1b839b62dd914 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 21 Feb 2023 23:16:25 +0000 Subject: Improve error message for typed constants that cannot be represented by a type --- src/check_expr.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 30e2c9ad8..c0920bde8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2116,16 +2116,21 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ o->mode = Addressing_Invalid; ); + ERROR_BLOCK(); + + if (is_type_numeric(o->type) && is_type_numeric(type)) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { - ERROR_BLOCK(); - error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s); + if (are_types_identical(o->type, type)) { + error(o->expr, "Numeric value '%s' cannot be represented by '%s', got %s", a, c, s); + } else { + error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s); + } check_assignment_error_suggestion(ctx, o, type); } } else { - ERROR_BLOCK(); error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); check_assignment_error_suggestion(ctx, o, type); } @@ -2597,10 +2602,12 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod x->type = t_untyped_integer; } + x->expr = node; x->value = exact_value_shift(be->op.kind, x_val, y_val); + if (is_type_typed(x->type)) { - check_is_expressible(c, x, base_type(x->type)); + check_is_expressible(c, x, x->type); } return; } -- cgit v1.2.3 From f5d507a9b9d20941bd86ba8559f710f21f0c8ccd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Feb 2023 11:30:08 +0000 Subject: Improve errors about conversions of constant integers --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/error.cpp | 33 ++++++++++++++++++++++------- 3 files changed, 82 insertions(+), 15 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 63e6514e0..7978aa0ef 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -578,7 +578,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr if (operand.mode == Addressing_Invalid || base_type(operand.type) == t_invalid) { gbString str = expr_to_string(init); - error(e->token, "Invalid declaration type '%s'", str); + error(init, "Invalid declaration value '%s'", str); gb_string_free(str); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c0920bde8..d7e7b29a4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2019,6 +2019,47 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } +gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type) { + if (is_type_integer(type) && o->value.kind == ExactValue_Integer) { + gbString b = type_to_string(type); + + i64 sz = type_size_of(type); + BigInt *bi = &o->value.value_integer; + if (is_type_unsigned(type)) { + if (big_int_is_neg(bi)) { + error_line("\tA negative value cannot be represented by the unsigned integer type '%s'\n", b); + } else { + BigInt one = big_int_make_u64(1); + BigInt max_size = big_int_make_u64(1); + BigInt bits = big_int_make_i64(8*sz); + big_int_shl_eq(&max_size, &bits); + big_int_sub_eq(&max_size, &one); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } + } else { + BigInt zero = big_int_make_u64(0); + BigInt one = big_int_make_u64(1); + BigInt max_size = big_int_make_u64(1); + BigInt bits = big_int_make_i64(8*sz - 1); + big_int_shl_eq(&max_size, &bits); + if (big_int_is_neg(bi)) { + big_int_neg(&max_size, &max_size); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } else { + big_int_sub_eq(&max_size, &one); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } + } + + gb_string_free(b); + + return true; + } + return false; +} gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); @@ -2050,6 +2091,8 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); + } else if (check_integer_exceed_suggestion(c, o, type)) { + return; } } @@ -2089,8 +2132,8 @@ gb_internal void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type } } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { error_line("\tSuggestion: a string may be transmuted to %s\n", b); - } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { - error_line("\tSuggestion: the expression may be casted to %s\n", b); + } else if (check_integer_exceed_suggestion(c, o, type)) { + return; } } @@ -2124,10 +2167,11 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { if (are_types_identical(o->type, type)) { - error(o->expr, "Numeric value '%s' cannot be represented by '%s', got %s", a, c, s); + error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); } else { - error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s); + error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); } + check_assignment_error_suggestion(ctx, o, type); } } else { @@ -2934,15 +2978,21 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { if (is_const_expr) { gbString val_str = exact_value_to_string(x->value); if (is_type_float(x->type) && is_type_integer(type)) { - error_line("\t%s cannot be expressed without truncation/rounding as the type '%s'\n", val_str, to_type); + error_line("\t%s cannot be represented without truncation/rounding as the type '%s'\n", val_str, to_type); // NOTE(bill): keep the mode and modify the type to minimize errors further on x->mode = Addressing_Constant; x->type = type; } else { - error_line("\t%s cannot be expressed as the type '%s'\n", val_str, to_type); + error_line("\t'%s' cannot be represented as the type '%s'\n", val_str, to_type); + if (is_type_numeric(type)) { + // NOTE(bill): keep the mode and modify the type to minimize errors further on + x->mode = Addressing_Constant; + x->type = type; + } } gb_string_free(val_str); + } check_cast_error_suggestion(c, x, type); diff --git a/src/error.cpp b/src/error.cpp index a0bb4ad5b..33157948f 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -97,15 +97,37 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { +// NOTE: defined in build_settings.cpp +gb_internal bool global_warnings_as_errors(void); +gb_internal bool global_ignore_warnings(void); +gb_internal bool show_error_line(void); +gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); + +gb_internal void warning(Token const &token, char const *fmt, ...); +gb_internal void error(Token const &token, char const *fmt, ...); +gb_internal void error(TokenPos pos, char const *fmt, ...); +gb_internal void error_line(char const *fmt, ...); +gb_internal void syntax_error(Token const &token, char const *fmt, ...); +gb_internal void syntax_error(TokenPos pos, char const *fmt, ...); +gb_internal void syntax_warning(Token const &token, char const *fmt, ...); +gb_internal void compiler_error(char const *fmt, ...); + gb_internal void begin_error_block(void) { mutex_lock(&global_error_collector.block_mutex); global_error_collector.in_block.store(true); } gb_internal void end_error_block(void) { - if (global_error_collector.error_buffer.count > 0) { - isize n = global_error_collector.error_buffer.count; - u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); + isize n = global_error_collector.error_buffer.count; + if (n > 0) { + u8 *text = global_error_collector.error_buffer.data; + if (show_error_line() && n >= 2 && !(text[n-2] == '\n' && text[n-1] == '\n')) { + // add an extra new line as padding when the error line is being shown + error_line("\n"); + } + + n = global_error_collector.error_buffer.count; + text = gb_alloc_array(permanent_allocator(), u8, n+1); gb_memmove(text, global_error_collector.error_buffer.data, n); text[n] = 0; String s = {text, n}; @@ -152,11 +174,6 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) { gb_global ErrorOutProc *error_out_va = default_error_out_va; -// NOTE: defined in build_settings.cpp -gb_internal bool global_warnings_as_errors(void); -gb_internal bool global_ignore_warnings(void); -gb_internal bool show_error_line(void); -gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); gb_internal void error_out(char const *fmt, ...) { va_list va; -- cgit v1.2.3 From 090e30f07b10a79edf38736cc466a4f223167971 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Feb 2023 11:48:10 +0000 Subject: Make `-verbose-errors` the default; `-terse-errors` to disable it --- src/build_settings.cpp | 4 ++-- src/check_expr.cpp | 6 +++++- src/error.cpp | 29 ++++++++++++++++++++++++----- src/exact_value.cpp | 4 +--- src/main.cpp | 9 ++++++++- 5 files changed, 40 insertions(+), 12 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a3873be82..ff372f418 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -288,7 +288,7 @@ struct BuildContext { bool ignore_warnings; bool warnings_as_errors; - bool show_error_line; + bool hide_error_line; bool ignore_lazy; bool ignore_llvm_build; @@ -1033,7 +1033,7 @@ gb_internal String get_fullpath_core(gbAllocator a, String path) { } gb_internal bool show_error_line(void) { - return build_context.show_error_line; + return !build_context.hide_error_line; } gb_internal bool has_asm_extension(String const &path) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d7e7b29a4..f42483c86 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1679,9 +1679,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { case Token_Not: if (!is_type_boolean(type)) { + ERROR_BLOCK(); str = expr_to_string(o->expr); - error(op, "Operator '%.*s' is only allowed on boolean expression", LIT(op.string)); + error(op, "Operator '%.*s' is only allowed on boolean expressions", LIT(op.string)); gb_string_free(str); + if (is_type_integer(type)) { + error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n"); + } } break; diff --git a/src/error.cpp b/src/error.cpp index 33157948f..cb2aa4836 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -121,7 +121,26 @@ gb_internal void end_error_block(void) { isize n = global_error_collector.error_buffer.count; if (n > 0) { u8 *text = global_error_collector.error_buffer.data; - if (show_error_line() && n >= 2 && !(text[n-2] == '\n' && text[n-1] == '\n')) { + + bool add_extra_newline = false; + + if (show_error_line()) { + if (n >= 2 && !(text[n-2] == '\n' && text[n-1] == '\n')) { + add_extra_newline = true; + } + } else { + isize newline_count = 0; + for (isize i = 0; i < n; i++) { + if (text[i] == '\n') { + newline_count += 1; + } + } + if (newline_count > 1) { + add_extra_newline = true; + } + } + + if (add_extra_newline) { // add an extra new line as padding when the error line is being shown error_line("\n"); } @@ -198,12 +217,12 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { // TODO(bill): This assumes ASCII enum { - MAX_LINE_LENGTH = 76, + MAX_LINE_LENGTH = 80, MAX_TAB_WIDTH = 8, - ELLIPSIS_PADDING = 8 + ELLIPSIS_PADDING = 8 // `... ...` }; - error_out("\n\t"); + error_out("\t"); if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { i32 const half_width = MAX_LINE_LENGTH/2; i32 left = cast(i32)(offset); @@ -244,7 +263,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { } } - error_out("\n\n"); + error_out("\n"); return true; } return false; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index fc4ae2155..1ab50800d 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -578,9 +578,7 @@ gb_internal ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i3 } } -failure: - GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op])); - +failure:; ExactValue error_value = {}; return error_value; } diff --git a/src/main.cpp b/src/main.cpp index 480930d4a..02996065a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -659,6 +659,7 @@ enum BuildFlagKind { BuildFlag_IgnoreWarnings, BuildFlag_WarningsAsErrors, + BuildFlag_TerseErrors, BuildFlag_VerboseErrors, BuildFlag_ErrorPosStyle, @@ -832,6 +833,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_TerseErrors, str_lit("terse-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all); @@ -1462,8 +1464,13 @@ gb_internal bool parse_build_flags(Array args) { } break; } + + case BuildFlag_TerseErrors: + build_context.hide_error_line = true; + break; case BuildFlag_VerboseErrors: - build_context.show_error_line = true; + gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n"); + build_context.hide_error_line = false; break; case BuildFlag_ErrorPosStyle: -- cgit v1.2.3 From 6a6d7701f9892a3468c74f0c7d1e70e04f529824 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 Feb 2023 21:50:49 +0000 Subject: Improve error bounds for `check_comparison` --- src/check_expr.cpp | 6 +++--- src/check_stmt.cpp | 8 ++++---- src/error.cpp | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f42483c86..00d394966 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2397,7 +2397,7 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t } -gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { +gb_internal void check_comparison(CheckerContext *c, Ast *node, 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) { @@ -2485,7 +2485,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok } if (err_str != nullptr) { - error(x->expr, "Cannot compare expression, %s", err_str); + error(node, "Cannot compare expression, %s", err_str); x->type = t_untyped_bool; } else { if (x->mode == Addressing_Constant && @@ -3498,7 +3498,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ if (token_is_comparison(op.kind)) { - check_comparison(c, x, y, op.kind); + check_comparison(c, node, x, y, op.kind); return; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index f300f45c7..7e3948336 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -978,19 +978,19 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags Operand a = lhs; Operand b = rhs; - check_comparison(ctx, &a, &x, Token_LtEq); + check_comparison(ctx, expr, &a, &x, Token_LtEq); if (a.mode == Addressing_Invalid) { continue; } - check_comparison(ctx, &b, &x, upper_op); + check_comparison(ctx, expr, &b, &x, upper_op); if (b.mode == Addressing_Invalid) { continue; } Operand a1 = lhs; Operand b1 = rhs; - check_comparison(ctx, &a1, &b1, Token_LtEq); + check_comparison(ctx, expr, &a1, &b1, Token_LtEq); add_to_seen_map(ctx, &seen, upper_op, x, lhs, rhs); @@ -1029,7 +1029,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags // NOTE(bill): the ordering here matters Operand z = y; - check_comparison(ctx, &z, &x, Token_CmpEq); + check_comparison(ctx, expr, &z, &x, Token_CmpEq); if (z.mode == Addressing_Invalid) { continue; } diff --git a/src/error.cpp b/src/error.cpp index 750cd147f..9279ed4d4 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -264,7 +264,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { ELLIPSIS_PADDING = 8 // `... ...` }; - error_out("\t"); + error_out("\n\t"); terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); @@ -345,6 +345,9 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va } else if (global_error_collector.prev != pos) { global_error_collector.prev = pos; error_out_pos(pos); + if (has_ansi_terminal_colours()) { + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + } error_out_va(fmt, va); error_out("\n"); show_error_on_line(pos, end); @@ -395,6 +398,9 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li } else if (global_error_collector.prev != pos) { global_error_collector.prev = pos; error_out_pos(pos); + if (has_ansi_terminal_colours()) { + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + } error_out_va(fmt, va); } mutex_unlock(&global_error_collector.mutex); -- cgit v1.2.3 From a9182cfd8cf9dd8cec125221e39c0fcd7a3fd3e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 26 Feb 2023 13:26:35 +0000 Subject: Allow compound literals to access fields through `using` --- src/check_expr.cpp | 205 +++++++++++++++++++++++++------------------ src/common.cpp | 5 ++ src/error.cpp | 4 +- src/llvm_backend_const.cpp | 77 +++++++++++++++- src/llvm_backend_expr.cpp | 20 ++++- src/llvm_backend_utility.cpp | 2 +- src/ptr_set.cpp | 2 +- src/types.cpp | 1 - 8 files changed, 219 insertions(+), 97 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 00d394966..b9588a798 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7890,6 +7890,124 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no return Expr_Expr; } + +gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice const &elems, Operand *o, Type *type, bool &is_constant) { + Type *bt = base_type(type); + + StringSet fields_visited = {}; + defer (string_set_destroy(&fields_visited)); + + StringMap fields_visited_through_raw_union = {}; + defer (string_map_destroy(&fields_visited_through_raw_union)); + + for (Ast *elem : elems) { + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(elem, "Invalid field name '%s' in structure literal", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + bool is_unknown = sel.entity == nullptr; + if (is_unknown) { + error(fv->field, "Unknown field '%.*s' in structure literal", LIT(name)); + continue; + } + + Entity *field = bt->Struct.fields[sel.index[0]]; + add_entity_use(c, fv->field, field); + if (string_set_update(&fields_visited, name)) { + if (sel.index.count > 1) { + if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { + error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + } else { + error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string)); + } + } else { + error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string)); + } + continue; + } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { + error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + continue; + } + if (sel.indirect) { + error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name)); + continue; + } + + if (sel.index.count > 1) { + if (is_constant) { + Type *ft = type; + for (i32 index : sel.index) { + Type *bt = base_type(ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + is_constant = false; + break; + } + ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + ft = bt->Array.elem; + break; + default: + GB_PANIC("invalid type: %s", type_to_string(ft)); + break; + } + } + if (is_constant && + (is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) { + is_constant = false; + } + } + + Type *nested_ft = bt; + for (i32 index : sel.index) { + Type *bt = base_type(nested_ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + for (Entity *re : bt->Struct.fields) { + string_map_set(&fields_visited_through_raw_union, re->token.string, sel.entity->token.string); + } + } + nested_ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + nested_ft = bt->Array.elem; + break; + default: + GB_PANIC("invalid type %s", type_to_string(nested_ft)); + break; + } + } + field = sel.entity; + } + + + Operand o = {}; + check_expr_or_type(c, &o, fv->value, field->type); + + if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -7977,45 +8095,13 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); gb_string_free(type_str); } else { - Ast *elem = cl->elems[0]; - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - break; - } - - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - break; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - break; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - - check_assignment(c, &o, field->type, str_lit("structure literal")); + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); } - } } break; } - isize field_count = t->Struct.fields.count; isize min_field_count = t->Struct.fields.count; for (isize i = min_field_count-1; i >= 0; i--) { @@ -8029,58 +8115,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (cl->elems[0]->kind == Ast_FieldValue) { - TEMPORARY_ALLOCATOR_GUARD(); - - bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); - - for (Ast *elem : cl->elems) { - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - continue; - } - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - continue; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - continue; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - if (fields_visited[sel.index[0]]) { - error(elem, "Duplicate field '%.*s' in structure literal", LIT(name)); - continue; - } - - fields_visited[sel.index[0]] = true; - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); } else { bool seen_field_value = false; diff --git a/src/common.cpp b/src/common.cpp index 859aa4a56..90632def3 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -53,6 +53,11 @@ struct TypeIsPointer { enum {value = true}; }; +template struct TypeIsPtrSizedInteger { enum {value = false}; }; +template <> struct TypeIsPtrSizedInteger { enum {value = true}; }; +template <> struct TypeIsPtrSizedInteger { enum {value = true}; }; + + #include "unicode.cpp" #include "array.cpp" #include "threading.cpp" diff --git a/src/error.cpp b/src/error.cpp index d20373be9..c684be1e7 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -423,7 +423,7 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const * error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red); error_out_va(fmt, va); error_out("\n"); - show_error_on_line(pos, end); + // show_error_on_line(pos, end); } else if (pos.line == 0) { error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red); error_out_va(fmt, va); @@ -451,7 +451,7 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); error_out_va(fmt, va); error_out("\n"); - show_error_on_line(pos, end); + // show_error_on_line(pos, end); } else if (pos.line == 0) { error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); error_out_va(fmt, va); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 72c2a0495..3da768cd1 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -386,6 +386,31 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi return value; } +gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, Ast *elem) { + GB_ASSERT(!sel.indirect); + for (i32 index : sel.index) { + Type *bt = base_type(ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + return false; + } + ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + ft = bt->Array.elem; + break; + default: + return false; + } + } + + + if (is_type_raw_union(ft) || is_type_typeid(ft)) { + return false; + } + return lb_is_elem_const(elem, ft); +} gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) { LLVMContextRef ctx = m->ctx; @@ -979,12 +1004,58 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(tav.mode != Addressing_Invalid); Selection sel = lookup_field(type, name, false); + GB_ASSERT(!sel.indirect); + Entity *f = type->Struct.fields[sel.index[0]]; - i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; - visited[index] = true; + if (sel.index.count == 1) { + values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + visited[index] = true; + } else { + if (!visited[index]) { + values[index] = lb_const_value(m, f->type, {}, false).value; + visited[index] = true; + } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; + unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); + + if (lb_is_nested_possibly_constant(type, sel, fv->value)) { + bool is_constant = true; + Type *cv_type = f->type; + for (isize j = 1; j < sel.index.count; j++) { + i32 index = sel.index[j]; + Type *cvt = base_type(cv_type); + + if (cvt->kind == Type_Struct) { + if (cvt->Struct.is_raw_union) { + // sanity check which should have been caught by `lb_is_nested_possibly_constant` + is_constant = false; + break; + } + cv_type = cvt->Struct.fields[index]->type; + + if (is_type_struct(cv_type)) { + auto cv_field_remapping = lb_get_struct_remapping(m, cv_type); + idx_list[j-1] = cast(unsigned)cv_field_remapping[index]; + } else { + idx_list[j-1] = cast(unsigned)index; + } + } else if (cvt->kind == Type_Array) { + cv_type = cvt->Array.elem; + + idx_list[j-1] = cast(unsigned)index; + } else { + GB_PANIC("UNKNOWN TYPE: %s", type_to_string(cv_type)); + } + } + if (is_constant) { + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local).value; + GB_ASSERT(LLVMIsConstant(elem_value)); + values[index] = LLVMConstInsertValue(values[index], elem_value, idx_list, idx_list_len); + } + } + } } } } else { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5bffc7226..3676847b4 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4044,7 +4044,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { return {}; } - gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(cl, CompoundLit, expr); @@ -4093,12 +4092,25 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; Selection sel = lookup_field(bt, name, false); - index = sel.index[0]; + GB_ASSERT(!sel.indirect); + elem = fv->value; - TypeAndValue tav = type_and_value_of_expr(elem); + if (sel.index.count > 1) { + if (lb_is_nested_possibly_constant(type, sel, elem)) { + continue; + } + lbValue dst = lb_emit_deep_field_gep(p, comp_lit_ptr, sel); + field_expr = lb_build_expr(p, elem); + field_expr = lb_emit_conv(p, field_expr, sel.entity->type); + lb_emit_store(p, dst, field_expr); + continue; + } + + index = sel.index[0]; } else { - TypeAndValue tav = type_and_value_of_expr(elem); Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); + GB_ASSERT(sel.index.count == 1); + GB_ASSERT(!sel.indirect); index = sel.index[0]; } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a4ef61531..19df9ab06 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -915,7 +915,7 @@ gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) if (field_remapping == nullptr) { field_remapping = map_get(&m->struct_field_remapping, cast(void *)t); } - GB_ASSERT(field_remapping != nullptr); + GB_ASSERT_MSG(field_remapping != nullptr, "%s", type_to_string(t)); return *field_remapping; } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 2b8f38fef..ff4befc37 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -1,6 +1,6 @@ template struct PtrSet { - static_assert(TypeIsPointer::value, "PtrSet::T must be a pointer"); + static_assert(TypeIsPointer::value || TypeIsPtrSizedInteger::value, "PtrSet::T must be a pointer"); static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull); T * keys; diff --git a/src/types.cpp b/src/types.cpp index 85364667d..ee610a2ce 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -430,7 +430,6 @@ gb_internal Selection sub_selection(Selection const &sel, isize offset) { return res; } - gb_global Type basic_types[] = { {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, -- cgit v1.2.3 From 1f17a391c62826f460f485d644f275f8e0d00630 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 27 Feb 2023 15:58:32 +0000 Subject: Improve error line squiggle logic --- src/check_expr.cpp | 4 ++-- src/error.cpp | 36 ++++++++++++++++++------------------ src/parser_pos.cpp | 4 ++-- 3 files changed, 22 insertions(+), 22 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b9588a798..29a673980 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4615,7 +4615,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod entity = scope_lookup_current(import_scope, entity_name); bool allow_builtin = false; if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { - error(op_expr, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); + error(node, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); operand->mode = Addressing_Invalid; operand->expr = node; @@ -4635,7 +4635,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (!is_entity_exported(entity, allow_builtin)) { gbString sel_str = expr_to_string(selector); - error(op_expr, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name)); + error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name)); gb_string_free(sel_str); // NOTE(bill): make the state valid still, even if it's "invalid" // operand->mode = Addressing_Invalid; diff --git a/src/error.cpp b/src/error.cpp index c684be1e7..2974dc039 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -261,30 +261,31 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { enum { MAX_LINE_LENGTH = 80, MAX_TAB_WIDTH = 8, - ELLIPSIS_PADDING = 8 // `... ...` + ELLIPSIS_PADDING = 8, // `... ...` + MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING, }; error_out("\t"); terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); - isize squiggle_extra = 0; - - if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { - i32 const half_width = MAX_LINE_LENGTH/2; - i32 left = cast(i32)(offset); - i32 right = cast(i32)(line.len - offset); - left = gb_min(left, half_width); - right = gb_min(right, half_width); - - line.text += offset-left; - line.len -= offset+right-left; - line = string_trim_whitespace(line); + i32 error_length = gb_max(end.offset - pos.offset, 1); - squiggle_extra = ELLIPSIS_PADDING/2 + 1; - offset = left + ELLIPSIS_PADDING/2; + isize squiggle_extra = 0; + if (line.len > MAX_LINE_LENGTH_PADDED) { + i32 left = MAX_TAB_WIDTH; + line.text += offset-left; + line.len -= offset-left; + offset = left+MAX_TAB_WIDTH/2; + if (line.len > MAX_LINE_LENGTH_PADDED) { + line.len = MAX_LINE_LENGTH_PADDED; + if (error_length > line.len-left) { + error_length = cast(i32)line.len - left; + squiggle_extra = 1; + } + } error_out("... %.*s ...", LIT(line)); } else { error_out("%.*s", LIT(line)); @@ -304,11 +305,10 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("~"); } } else if (end.line == pos.line && end.column > pos.column) { - i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset)); - for (i32 i = 1; i < length-1+squiggle_extra; i++) { + for (i32 i = 1; i < error_length-1+squiggle_extra; i++) { error_out("~"); } - if (length > 1 && squiggle_extra == 0) { + if (error_length > 1 && squiggle_extra == 0) { error_out("^"); } } diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index fb7f0c9c2..8a0c3eca6 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -20,8 +20,8 @@ gb_internal Token ast_token(Ast *node) { case Ast_ParenExpr: return node->ParenExpr.open; case Ast_CallExpr: return ast_token(node->CallExpr.proc); case Ast_SelectorExpr: - if (node->SelectorExpr.selector != nullptr) { - return ast_token(node->SelectorExpr.selector); + if (node->SelectorExpr.expr != nullptr) { + return ast_token(node->SelectorExpr.expr); } return node->SelectorExpr.token; case Ast_SelectorCallExpr: -- cgit v1.2.3 From 2d71ab6f2907c14651da8fb231a695b4a60f2c68 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 2 Mar 2023 14:54:27 +0000 Subject: Improve error message on undefined operators --- src/check_expr.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b4836416e..5338c0b67 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2455,12 +2455,11 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper } if (!defined) { - if (x->type == err_type && is_operand_nil(*x)) { - err_type = y->type; - } - gbString type_string = type_to_string(err_type, temporary_allocator()); + gbString xs = type_to_string(x->type, temporary_allocator()); + gbString ys = type_to_string(y->type, temporary_allocator()); err_str = gb_string_make(temporary_allocator(), - gb_bprintf("operator '%.*s' not defined for type '%s'", LIT(token_strings[op]), type_string)); + gb_bprintf("operator '%.*s' not defined between the types '%s' and '%s'", LIT(token_strings[op]), xs, ys) + ); } else { Type *comparison_type = x->type; if (x->type == err_type && is_operand_nil(*x)) { -- cgit v1.2.3 From 49cf0125a936bdc5406ec7dcb0837470992f676c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 16 Mar 2023 13:01:06 +0000 Subject: Fix minor memory leak --- src/check_expr.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5338c0b67..f27675301 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6800,14 +6800,21 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c operand->type = t_invalid; } } else { - gbString str = type_to_string(t); - defer (gb_string_free(str)); - operand->mode = Addressing_Invalid; isize arg_count = args.count; switch (arg_count) { - case 0: error(call, "Missing argument in conversion to '%s'", str); break; - default: error(call, "Too many arguments in conversion to '%s'", str); break; + case 0: + { + gbString str = type_to_string(t); + error(call, "Missing argument in conversion to '%s'", str); + gb_string_free(str); + } break; + default: + { + gbString str = type_to_string(t); + error(call, "Too many arguments in conversion to '%s'", str); + gb_string_free(str); + } break; case 1: { Ast *arg = args[0]; if (arg->kind == Ast_FieldValue) { -- cgit v1.2.3 From 5da76ae34bac2f54b1bda5528cf49c0551e88bba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Apr 2023 15:36:21 +0100 Subject: Add `struct #no_copy` --- core/runtime/core.odin | 1 + src/check_decl.cpp | 8 ++++++++ src/check_expr.cpp | 20 ++++++++++++++++++++ src/check_stmt.cpp | 4 +++- src/check_type.cpp | 5 +++-- src/llvm_backend_type.cpp | 16 +++++++++------- src/parser.cpp | 11 +++++++++-- src/parser.hpp | 1 + src/types.cpp | 7 +++++++ 9 files changed, 61 insertions(+), 12 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 040590b4a..9939bfc5c 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -119,6 +119,7 @@ Type_Info_Struct :: struct { tags: []string, is_packed: bool, is_raw_union: bool, + is_no_copy: bool, custom_align: bool, equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5c25dd6a3..5a8080f96 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -131,6 +131,14 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l if (d != nullptr) { d->init_expr = o->expr; } + + if (o->type && is_type_no_copy(o->type)) { + begin_error_block(); + if (check_no_copy_assignment(*o, str_lit("initialization"))) { + error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or from a return value a call expression"); + } + end_error_block(); + } } if (rhs_count > 0 && lhs_count != rhs_count) { error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f27675301..e55765ff8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5043,6 +5043,21 @@ gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lh return tuple_count; } +gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) { + if (o.type && is_type_no_copy(o.type)) { + Ast *expr = unparen_expr(o.expr); + if (expr && o.mode != Addressing_Constant) { + if (expr->kind == Ast_CallExpr) { + // Okay + } else { + error(o.expr, "Invalid use a #no_copy value in %.*s", LIT(context)); + return true; + } + } + } + return false; +} + gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { bool optional_ok = false; @@ -5114,6 +5129,7 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array for (Entity *e : tuple->variables) { o.type = e->type; array_add(operands, o); + check_no_copy_assignment(o, str_lit("assignment")); } tuple_index += tuple->variables.count; @@ -5952,6 +5968,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } } + for (Operand const &o : operands) { + check_no_copy_assignment(o, str_lit("call expression")); + } + if (operand->mode == Addressing_ProcGroup) { check_entity_decl(c, operand->proc_group, nullptr, nullptr); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 4e6623fc1..388a64e00 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -326,7 +326,6 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) { - gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { if (rhs->mode == Addressing_Invalid) { return nullptr; @@ -339,6 +338,8 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Ast *node = unparen_expr(lhs->expr); + check_no_copy_assignment(*rhs, str_lit("assignment")); + // NOTE(bill): Ignore assignments to '_' if (is_blank_ident(node)) { check_assignment(ctx, rhs, nullptr, str_lit("assignment to '_' identifier")); @@ -400,6 +401,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } Type *assignment_type = lhs->type; + switch (lhs->mode) { case Addressing_Invalid: return nullptr; diff --git a/src/check_type.cpp b/src/check_type.cpp index 7444f88be..b687e838e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -609,8 +609,9 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * context = str_lit("struct #raw_union"); } - struct_type->Struct.scope = ctx->scope; - struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.scope = ctx->scope; + struct_type->Struct.is_packed = st->is_packed; + struct_type->Struct.is_no_copy = st->is_no_copy; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index e8d286fda..3af10112f 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -691,32 +691,34 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup case Type_Struct: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - LLVMValueRef vals[12] = {}; + LLVMValueRef vals[13] = {}; { lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed); lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union); + lbValue is_no_copy = lb_const_bool(m, t_bool, t->Struct.is_no_copy); lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0); vals[5] = is_packed.value; vals[6] = is_raw_union.value; - vals[7] = is_custom_align.value; + vals[7] = is_no_copy.value; + vals[8] = is_custom_align.value; if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[8] = lb_equal_proc_for_type(m, t).value; + vals[9] = lb_equal_proc_for_type(m, t).value; } if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 9); + lbValue kind = lb_emit_struct_ep(p, tag, 10); Type *kind_type = type_deref(kind.type); lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); - vals[9] = soa_kind.value; - vals[10] = soa_type.value; - vals[11] = soa_len.value; + vals[10] = soa_kind.value; + vals[11] = soa_type.value; + vals[12] = soa_len.value; } } diff --git a/src/parser.cpp b/src/parser.cpp index 50a9ba766..790e67db6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1047,7 +1047,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { } gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, isize field_count, - Ast *polymorphic_params, bool is_packed, bool is_raw_union, + Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy, Ast *align, Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); @@ -1057,6 +1057,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice fields, i result->StructType.polymorphic_params = polymorphic_params; result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; + result->StructType.is_no_copy = is_no_copy; result->StructType.align = align; result->StructType.where_token = where_token; result->StructType.where_clauses = slice_from_array(where_clauses); @@ -2392,6 +2393,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { Ast *polymorphic_params = nullptr; bool is_packed = false; bool is_raw_union = false; + bool no_copy = false; Ast *align = nullptr; if (allow_token(f, Token_OpenParen)) { @@ -2427,6 +2429,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_raw_union = true; + } else if (tag.string == "no_copy") { + if (is_packed) { + syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); + } + no_copy = true; } else { syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string)); } @@ -2465,7 +2472,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { decls = fields->FieldList.list; } - return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses); + return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, where_token, where_clauses); } break; case Token_union: { diff --git a/src/parser.hpp b/src/parser.hpp index 5e1878cf2..5302fd274 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -693,6 +693,7 @@ AST_KIND(_TypeBegin, "", bool) \ Slice where_clauses; \ bool is_packed; \ bool is_raw_union; \ + bool is_no_copy; \ }) \ AST_KIND(UnionType, "union type", struct { \ Scope *scope; \ diff --git a/src/types.cpp b/src/types.cpp index 5addb5b7b..889269564 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -149,6 +149,7 @@ struct TypeStruct { bool are_offsets_being_processed : 1; bool is_packed : 1; bool is_raw_union : 1; + bool is_no_copy : 1; bool is_poly_specialized : 1; }; @@ -1670,6 +1671,10 @@ gb_internal bool is_type_raw_union(Type *t) { t = base_type(t); return (t->kind == Type_Struct && t->Struct.is_raw_union); } +gb_internal bool is_type_no_copy(Type *t) { + t = base_type(t); + return (t->kind == Type_Struct && t->Struct.is_no_copy); +} gb_internal bool is_type_enum(Type *t) { t = base_type(t); return (t->kind == Type_Enum); @@ -2655,6 +2660,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Struct: if (x->Struct.is_raw_union == y->Struct.is_raw_union && + x->Struct.is_no_copy == y->Struct.is_no_copy && x->Struct.fields.count == y->Struct.fields.count && x->Struct.is_packed == y->Struct.is_packed && x->Struct.custom_align == y->Struct.custom_align && @@ -4207,6 +4213,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, "struct"); if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); + if (type->Struct.is_no_copy) str = gb_string_appendc(str, " #no_copy"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); str = gb_string_appendc(str, " {"); -- cgit v1.2.3 From e24315eed892aeb6c53da78c415455a80ccdf5e5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Apr 2023 16:16:16 +0100 Subject: Improve grammar --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5a8080f96..a984f87a3 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -135,7 +135,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l if (o->type && is_type_no_copy(o->type)) { begin_error_block(); if (check_no_copy_assignment(*o, str_lit("initialization"))) { - error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or from a return value a call expression"); + error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression"); } end_error_block(); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e55765ff8..de9a6b911 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5050,7 +5050,7 @@ gb_internal bool check_no_copy_assignment(Operand const &o, String const &contex if (expr->kind == Ast_CallExpr) { // Okay } else { - error(o.expr, "Invalid use a #no_copy value in %.*s", LIT(context)); + error(o.expr, "Invalid use of #no_copy value in %.*s", LIT(context)); return true; } } -- cgit v1.2.3 From 6726df4d58b2538014b1e9487eddd8de26bc89fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Apr 2023 11:20:15 +0100 Subject: Allow aliasing foreign import name --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index de9a6b911..42306489b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1631,7 +1631,9 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam } return e; case Entity_LibraryName: - error(n, "Use of library '%.*s' not in foreign block", LIT(name)); + if (!allow_import_name) { + error(n, "Use of library '%.*s' not in foreign block", LIT(name)); + } return e; case Entity_Label: -- cgit v1.2.3 From b0f0a02d3c897c91350501fcf3d8c2f03886a82f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 27 Apr 2023 11:26:15 +0100 Subject: Make `!x` be an untyped boolean --- src/check_expr.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 42306489b..6eb517251 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1688,6 +1688,8 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { if (is_type_integer(type)) { error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n"); } + } else { + o->type = t_untyped_bool; } break; -- cgit v1.2.3 From 171f38b9b5c0e46de98829b3f775cef5e27279be Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 18 May 2023 11:06:02 +0100 Subject: Allow implicit conversion between boolean types within `or_return` This is to improve the experience using third-party code, especially foreign C-like code which may use a distinct boolean or a different sized one --- src/check_expr.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6eb517251..0db12aba0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7887,8 +7887,11 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no rhs.type = right_type; rhs.mode = Addressing_Value; - // TODO(bill): better error message - if (!check_is_assignable_to(c, &rhs, end_type)) { + if (is_type_boolean(right_type) && is_type_boolean(end_type)) { + // NOTE(bill): allow implicit conversion between boolean types + // within 'or_return' to improve the experience using third-party code + } else if (!check_is_assignable_to(c, &rhs, end_type)) { + // TODO(bill): better error message gbString a = type_to_string(right_type); gbString b = type_to_string(end_type); gbString ret_type = type_to_string(result_type); -- cgit v1.2.3 From 2631e07beab29558249341c329c69bb604dd61fb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 19 May 2023 11:18:20 +0100 Subject: Add `intrinsics.type_merge` --- core/intrinsics/intrinsics.odin | 1 + src/check_builtin.cpp | 69 +++++++++++++++++++++++++++++++++++++++++ src/check_expr.cpp | 2 +- src/checker_builtin_procs.hpp | 2 ++ src/parser.hpp | 9 ++++++ 5 files changed, 82 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 890a6881d..93cd0e505 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -192,6 +192,7 @@ type_map_info :: proc($T: typeid/map[$K]$V) -> ^runtime.Map_Info --- type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- +type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5f9715959..0f8cdfd69 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4843,6 +4843,75 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Type; break; + case BuiltinProc_type_merge: + { + operand->mode = Addressing_Type; + operand->type = t_invalid; + + Operand x = {}; + Operand y = {}; + check_expr_or_type(c, &x, ce->args[0]); + check_expr_or_type(c, &y, ce->args[1]); + if (x.mode != Addressing_Type) { + error(x.expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (y.mode != Addressing_Type) { + error(y.expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + + if (is_type_polymorphic(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (is_type_polymorphic(y.type)) { + gbString t = type_to_string(y.type); + error(y.expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!is_type_union(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + if (!is_type_union(y.type)) { + gbString t = type_to_string(y.type); + error(x.expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + Type *ux = base_type(x.type); + Type *uy = base_type(y.type); + GB_ASSERT(ux->kind == Type_Union); + GB_ASSERT(uy->kind == Type_Union); + + i64 custom_align = gb_max(ux->Union.custom_align, uy->Union.custom_align); + if (ux->Union.kind != uy->Union.kind) { + error(x.expr, "Union kinds must match, got %s vs %s", union_type_kind_strings[ux->Union.kind], union_type_kind_strings[uy->Union.kind]); + } + + Type *merged_union = alloc_type_union(); + + merged_union->Union.node = call; + merged_union->Union.scope = create_scope(c->info, c->scope); + merged_union->Union.kind = ux->Union.kind; + merged_union->Union.custom_align = custom_align; + + auto variants = slice_make(permanent_allocator(), ux->Union.variants.count+uy->Union.variants.count); + slice_copy(&variants, ux->Union.variants, 0); + slice_copy(&variants, uy->Union.variants, ux->Union.variants.count); + merged_union->Union.variants = variants; + + operand->mode = Addressing_Type; + operand->type = merged_union; + } + break; + case BuiltinProc_type_is_boolean: case BuiltinProc_type_is_integer: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0db12aba0..1552b1ef5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1067,7 +1067,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ if (check_is_assignable_to(c, operand, type)) { if (operand->mode == Addressing_Type && is_type_typeid(type)) { - add_type_info_type(c, operand->type); + add_type_info_type(c, operand->type); add_type_and_value(c, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); } } else { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 72f001c70..edd046087 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -203,6 +203,7 @@ BuiltinProc__type_begin, BuiltinProc_type_elem_type, BuiltinProc_type_convert_variants_to_pointers, + BuiltinProc_type_merge, BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_boolean, @@ -501,6 +502,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/parser.hpp b/src/parser.hpp index 5302fd274..aea3bbf21 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -356,6 +356,15 @@ enum UnionTypeKind : u8 { UnionType_Normal = 0, UnionType_no_nil = 2, UnionType_shared_nil = 3, + + UnionType_COUNT +}; + +gb_global char const *union_type_kind_strings[UnionType_COUNT] = { + "(normal)", + "#maybe", + "#no_nil", + "#shared_nil", }; #define AST_KINDS \ -- cgit v1.2.3 From d5a8f2298e68c64f2f9e2fe5d0c6ab528db627a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 12:37:26 +0100 Subject: Restrict `---` to variable declarations only --- src/check_decl.cpp | 2 +- src/check_expr.cpp | 31 +++++++++++++++++++++++++------ src/check_stmt.cpp | 2 +- 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index e97e86e8b..b16215571 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -123,7 +123,7 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l // an extra allocation TEMPORARY_ALLOCATOR_GUARD(); auto operands = array_make(temporary_allocator(), 0, 2*lhs_count); - check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false); + check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, UnpackFlag_AllowOk|UnpackFlag_AllowUndef); isize rhs_count = operands.count; isize max = gb_min(lhs_count, rhs_count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1552b1ef5..e0e74a3aa 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5144,8 +5144,20 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array } +typedef u32 UnpackFlags; +enum UnpackFlag : u32 { + UnpackFlag_None = 0, + UnpackFlag_AllowOk = 1<<0, + UnpackFlag_IsVariadic = 1<<1, + UnpackFlag_AllowUndef = 1<<2, +}; + + +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, UnpackFlags flags) { + bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; + bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; + bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; -gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, bool allow_ok, bool is_variadic) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -5184,7 +5196,13 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } } - check_expr_base(c, &o, rhs[i], type_hint); + if (allow_undef && rhs[i] != nullptr && rhs[i]->kind == Ast_Undef) { + o.type = t_untyped_undef; + o.mode = Addressing_Value; + o.expr = rhs[i]; + } else { + check_expr_base(c, &o, rhs[i], type_hint); + } if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); o.mode = Addressing_Invalid; @@ -5968,7 +5986,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); } if (operand->mode != Addressing_ProcGroup) { - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } } @@ -6025,7 +6043,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op isize lhs_count = -1; bool is_variadic = false; lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data); @@ -6101,7 +6119,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } - check_unpack_arguments(c, lhs, lhs_count, &operands, args, false, false); + check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None); if (lhs != nullptr) { gb_free(heap_allocator(), lhs); @@ -6462,7 +6480,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O lhs_count = params->variables.count; } - check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, false, false); + check_unpack_arguments(c, lhs, lhs_count, &operands, ce->args, UnpackFlag_None); } } @@ -9583,6 +9601,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(u, Undef, node); o->mode = Addressing_Value; o->type = t_untyped_undef; + error(node, "Use of --- outside of variable declaration"); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1e3b35c21..6c69ad59f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2176,7 +2176,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { auto operands = array_make(heap_allocator(), 0, 2*rs->results.count); defer (array_free(&operands)); - check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, true, false); + check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk); if (result_count == 0 && rs->results.count > 0) { error(rs->results[0], "No return values expected"); -- cgit v1.2.3 From 540f724b1f57d0d5a40b65a59f6ee82e070c6ee5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 12:42:02 +0100 Subject: Fix `---` on variable declarations --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e0e74a3aa..20a690e1e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5196,10 +5196,13 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } } - if (allow_undef && rhs[i] != nullptr && rhs[i]->kind == Ast_Undef) { + Ast *rhs_expr = unparen_expr(rhs[i]); + if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Undef) { + // NOTE(bill): Just handle this very specific logic here o.type = t_untyped_undef; o.mode = Addressing_Value; o.expr = rhs[i]; + add_type_and_value(c, rhs[i], o.mode, o.type, o.value); } else { check_expr_base(c, &o, rhs[i], type_hint); } -- cgit v1.2.3 From 8bf32ac697ea21ff3b37e5b31fe0fc10e700c9a4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 22 May 2023 12:53:29 +0100 Subject: Minor change to handling of propagation of errors with `---` as a value --- src/check_decl.cpp | 9 ++++----- src/check_expr.cpp | 45 +++++++++++++++++++++----------------------- src/check_type.cpp | 6 +++--- src/checker.cpp | 4 ++-- src/llvm_backend.cpp | 10 ++-------- src/llvm_backend_const.cpp | 2 +- src/llvm_backend_debug.cpp | 2 +- src/llvm_backend_expr.cpp | 16 ++++++++-------- src/llvm_backend_general.cpp | 4 ++-- src/llvm_backend_proc.cpp | 8 ++++---- src/parser.cpp | 14 +++++++------- src/parser.hpp | 2 +- src/parser_pos.cpp | 4 ++-- src/tokenizer.cpp | 6 +++--- src/types.cpp | 19 ++++++++----------- 15 files changed, 69 insertions(+), 82 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index b16215571..84b0d39d8 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -70,13 +70,12 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o // NOTE(bill): Use the type of the operand Type *t = operand->type; if (is_type_untyped(t)) { - if (t == t_invalid || is_type_untyped_nil(t)) { - error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name)); + if (is_type_untyped_uninit(t)) { + error(e->token, "Invalid use of --- in %.*s", LIT(context_name)); e->type = t_invalid; return nullptr; - } - if (t == t_invalid || is_type_untyped_undef(t)) { - error(e->token, "Invalid use of --- in %.*s", LIT(context_name)); + } else if (t == t_invalid || is_type_untyped_nil(t)) { + error(e->token, "Invalid use of untyped nil in %.*s", LIT(context_name)); e->type = t_invalid; return nullptr; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 20a690e1e..830b5315d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -646,11 +646,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand Type *src = base_type(s); Type *dst = base_type(type); - if (is_type_untyped_undef(src)) { - if (type_has_undef(dst)) { - return 1; - } - return -1; + if (is_type_untyped_uninit(src)) { + return 1; } if (is_type_untyped_nil(src)) { @@ -993,13 +990,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ if (is_type_untyped(operand->type)) { Type *target_type = type; if (type == nullptr || is_type_any(type)) { - if (type == nullptr && is_type_untyped_nil(operand->type)) { - error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name)); + if (type == nullptr && is_type_untyped_uninit(operand->type)) { + error(operand->expr, "Use of --- in %.*s", LIT(context_name)); operand->mode = Addressing_Invalid; return; } - if (type == nullptr && is_type_untyped_undef(operand->type)) { - error(operand->expr, "Use of --- in %.*s", LIT(context_name)); + if (type == nullptr && is_type_untyped_nil(operand->type)) { + error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name)); operand->mode = Addressing_Invalid; return; } @@ -3969,7 +3966,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: - if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { + if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) { TEMPORARY_ALLOCATOR_GUARD(); isize count = t->Union.variants.count; @@ -4036,8 +4033,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar error_line("\n\n"); return; - } else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { - target_type = t_untyped_undef; + } else if (is_type_untyped_uninit(operand->type)) { + target_type = t_untyped_uninit; } else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { begin_error_block(); defer (end_error_block()); @@ -4070,8 +4067,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar default: - if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { - target_type = t_untyped_undef; + if (is_type_untyped_uninit(operand->type)) { + target_type = t_untyped_uninit; } else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) { target_type = t_untyped_nil; } else { @@ -4083,8 +4080,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } if (is_type_any(target_type) && is_type_untyped(operand->type)) { - if (is_type_untyped_nil(operand->type) && is_type_untyped_undef(operand->type)) { - + if (is_type_untyped_nil(operand->type) && is_type_untyped_uninit(operand->type)) { + } else { target_type = default_type(operand->type); } @@ -5197,9 +5194,9 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } Ast *rhs_expr = unparen_expr(rhs[i]); - if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Undef) { + if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Uninit) { // NOTE(bill): Just handle this very specific logic here - o.type = t_untyped_undef; + o.type = t_untyped_uninit; o.mode = Addressing_Value; o.expr = rhs[i]; add_type_and_value(c, rhs[i], o.mode, o.type, o.value); @@ -7167,11 +7164,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 } gb_internal bool ternary_compare_types(Type *x, Type *y) { - if (is_type_untyped_undef(x) && type_has_undef(y)) { + if (is_type_untyped_uninit(x)) { return true; } else if (is_type_untyped_nil(x) && type_has_nil(y)) { return true; - } else if (is_type_untyped_undef(y) && type_has_undef(x)) { + } else if (is_type_untyped_uninit(y)) { return true; } else if (is_type_untyped_nil(y) && type_has_nil(x)) { return true; @@ -7708,7 +7705,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n } o->type = x.type; - if (is_type_untyped_nil(o->type) || is_type_untyped_undef(o->type)) { + if (is_type_untyped_nil(o->type) || is_type_untyped_uninit(o->type)) { o->type = y.type; } @@ -9601,9 +9598,9 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast check_ident(c, o, node, nullptr, type_hint, false); case_end; - case_ast_node(u, Undef, node); + case_ast_node(u, Uninit, node); o->mode = Addressing_Value; - o->type = t_untyped_undef; + o->type = t_untyped_uninit; error(node, "Use of --- outside of variable declaration"); case_end; @@ -10167,7 +10164,7 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan str = string_append_string(str, bd->name.string); case_end; - case_ast_node(ud, Undef, node); + case_ast_node(ud, Uninit, node); str = gb_string_appendc(str, "---"); case_end; diff --git a/src/check_type.cpp b/src/check_type.cpp index dfe774f6b..bbfc25a12 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -135,7 +135,7 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slicemodule, var.var); - if (is_type_untyped_undef(init.type)) { - // LLVMSetInitializer(var.var.value, LLVMGetUndef(global_type)); - LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); - var.is_initialized = true; - continue; - } else if (is_type_untyped_nil(init.type)) { + if (is_type_untyped_nil(init.type)) { LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); var.is_initialized = true; continue; @@ -2363,8 +2358,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } } - if (!var.is_initialized && - (is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) { + if (!var.is_initialized && is_type_untyped_nil(tav.type)) { var.is_initialized = true; } } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 8db6e2a1f..ea25a4594 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1,6 +1,6 @@ gb_internal bool lb_is_const(lbValue value) { LLVMValueRef v = value.value; - if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) { + if (is_type_untyped_nil(value.type)) { // TODO(bill): Is this correct behaviour? return true; } diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index fd26c41a0..bec719a4a 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -282,7 +282,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; - case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; + case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break; default: GB_PANIC("Basic Unhandled"); break; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 69443c9a3..143e38a8d 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1486,12 +1486,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { GB_ASSERT(src != nullptr); GB_ASSERT(dst != nullptr); + if (is_type_untyped_uninit(src)) { + return lb_const_undef(m, t); + } if (is_type_untyped_nil(src)) { return lb_const_nil(m, t); } - if (is_type_untyped_undef(src)) { - return lb_const_undef(m, t); - } if (LLVMIsConstant(value.value)) { if (is_type_any(dst)) { @@ -2132,12 +2132,12 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { if (is_type_any(dst)) { + if (is_type_untyped_uninit(src)) { + return lb_const_undef(p->module, t); + } if (is_type_untyped_nil(src)) { return lb_const_nil(p->module, t); } - if (is_type_untyped_undef(src)) { - return lb_const_undef(p->module, t); - } lbAddr result = lb_add_local_generated(p, t, true); @@ -3136,11 +3136,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { return lb_addr_load(p, lb_build_addr(p, expr)); case_end; - case_ast_node(u, Undef, expr) + case_ast_node(u, Uninit, expr) lbValue res = {}; if (is_type_untyped(type)) { res.value = nullptr; - res.type = t_untyped_undef; + res.type = t_untyped_uninit; } else { res.value = LLVMGetUndef(lb_type(m, type)); res.type = type; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7d2f574fe..628c1e5fa 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -677,7 +677,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { return; } GB_ASSERT(value.type != nullptr); - if (is_type_untyped_undef(value.type)) { + if (is_type_untyped_uninit(value.type)) { Type *t = lb_addr_type(addr); value.type = t; value.value = LLVMGetUndef(lb_type(p->module, t)); @@ -1828,7 +1828,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; - case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; + case Basic_UntypedUninit: GB_PANIC("Basic_UntypedUninit"); break; } break; case Type_Named: diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ddf058668..b8353a466 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3218,10 +3218,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { Entity *e = params->variables[i]; if (args[i].type == nullptr) { continue; + } else if (is_type_untyped_uninit(args[i].type)) { + args[i] = lb_const_undef(m, e->type); } else if (is_type_untyped_nil(args[i].type)) { args[i] = lb_const_nil(m, e->type); - } else if (is_type_untyped_undef(args[i].type)) { - args[i] = lb_const_undef(m, e->type); } } @@ -3409,10 +3409,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { Entity *e = param_tuple->variables[i]; if (args[i].type == nullptr) { continue; + } else if (is_type_untyped_uninit(args[i].type)) { + args[i] = lb_const_undef(m, e->type); } else if (is_type_untyped_nil(args[i].type)) { args[i] = lb_const_nil(m, e->type); - } else if (is_type_untyped_undef(args[i].type)) { - args[i] = lb_const_undef(m, e->type); } } } diff --git a/src/parser.cpp b/src/parser.cpp index 698ba99ab..bb492fca9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -115,7 +115,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { n->Ident.entity = nullptr; break; case Ast_Implicit: break; - case Ast_Undef: break; + case Ast_Uninit: break; case Ast_BasicLit: break; case Ast_BasicDirective: break; @@ -646,9 +646,9 @@ gb_internal Ast *ast_implicit(AstFile *f, Token token) { result->Implicit = token; return result; } -gb_internal Ast *ast_undef(AstFile *f, Token token) { - Ast *result = alloc_ast_node(f, Ast_Undef); - result->Undef = token; +gb_internal Ast *ast_uninit(AstFile *f, Token token) { + Ast *result = alloc_ast_node(f, Ast_Uninit); + result->Uninit = token; return result; } @@ -2092,8 +2092,8 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { case Token_Ident: return parse_ident(f); - case Token_Undef: - return ast_undef(f, expect_token(f, Token_Undef)); + case Token_Uninit: + return ast_uninit(f, expect_token(f, Token_Uninit)); case Token_context: return ast_implicit(f, expect_token(f, Token_context)); @@ -2292,7 +2292,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { skip_possible_newline_for_literal(f); - if (allow_token(f, Token_Undef)) { + if (allow_token(f, Token_Uninit)) { if (where_token.kind != Token_Invalid) { syntax_error(where_token, "'where' clauses are not allowed on procedure literals without a defined body (replaced with ---)"); } diff --git a/src/parser.hpp b/src/parser.hpp index aea3bbf21..d4883f287 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -373,7 +373,7 @@ gb_global char const *union_type_kind_strings[UnionType_COUNT] = { Entity *entity; \ }) \ AST_KIND(Implicit, "implicit", Token) \ - AST_KIND(Undef, "undef", Token) \ + AST_KIND(Uninit, "uninitialized value", Token) \ AST_KIND(BasicLit, "basic literal", struct { \ Token token; \ }) \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 1274f05a0..52d49e897 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -2,7 +2,7 @@ gb_internal Token ast_token(Ast *node) { switch (node->kind) { case Ast_Ident: return node->Ident.token; case Ast_Implicit: return node->Implicit; - case Ast_Undef: return node->Undef; + case Ast_Uninit: return node->Uninit; case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicDirective: return node->BasicDirective.token; case Ast_ProcGroup: return node->ProcGroup.token; @@ -137,7 +137,7 @@ Token ast_end_token(Ast *node) { return empty_token; case Ast_Ident: return node->Ident.token; case Ast_Implicit: return node->Implicit; - case Ast_Undef: return node->Undef; + case Ast_Uninit: return node->Uninit; case Ast_BasicLit: return node->BasicLit.token; case Ast_BasicDirective: return node->BasicDirective.token; case Ast_ProcGroup: return node->ProcGroup.close; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 547a864fb..17a396b9f 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -54,7 +54,7 @@ TOKEN_KIND(Token__AssignOpEnd, ""), \ TOKEN_KIND(Token_Increment, "++"), \ TOKEN_KIND(Token_Decrement, "--"), \ TOKEN_KIND(Token_ArrowRight,"->"), \ - TOKEN_KIND(Token_Undef, "---"), \ + TOKEN_KIND(Token_Uninit, "---"), \ \ TOKEN_KIND(Token__ComparisonBegin, ""), \ TOKEN_KIND(Token_CmpEq, "=="), \ @@ -917,7 +917,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { token->kind = Token_Decrement; if (t->curr_rune == '-') { advance_to_next_rune(t); - token->kind = Token_Undef; + token->kind = Token_Uninit; } break; case '>': @@ -1078,7 +1078,7 @@ semicolon_check:; case Token_Imag: case Token_Rune: case Token_String: - case Token_Undef: + case Token_Uninit: /*fallthrough*/ case Token_Question: case Token_Pointer: diff --git a/src/types.cpp b/src/types.cpp index 70c4bcdbe..35fbb719b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -83,7 +83,7 @@ enum BasicKind { Basic_UntypedString, Basic_UntypedRune, Basic_UntypedNil, - Basic_UntypedUndef, + Basic_UntypedUninit, Basic_COUNT, @@ -515,7 +515,7 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, - {Type_Basic, {Basic_UntypedUndef, BasicFlag_Untyped, 0, STR_LIT("untyped undefined")}}, + {Type_Basic, {Basic_UntypedUninit, BasicFlag_Untyped, 0, STR_LIT("untyped uninitialized")}}, }; // gb_global Type basic_type_aliases[] = { @@ -589,7 +589,7 @@ gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; -gb_global Type *t_untyped_undef = &basic_types[Basic_UntypedUndef]; +gb_global Type *t_untyped_uninit = &basic_types[Basic_UntypedUninit]; @@ -1866,14 +1866,15 @@ gb_internal bool is_type_typeid(Type *t) { } gb_internal bool is_type_untyped_nil(Type *t) { t = base_type(t); - return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedNil); + // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling + return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit)); } -gb_internal bool is_type_untyped_undef(Type *t) { +gb_internal bool is_type_untyped_uninit(Type *t) { t = base_type(t); - return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUndef); + // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling + return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit); } - gb_internal bool is_type_empty_union(Type *t) { t = base_type(t); return t->kind == Type_Union && t->Union.variants.count == 0; @@ -2206,10 +2207,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { } -gb_internal gb_inline bool type_has_undef(Type *t) { - return true; -} - gb_internal bool type_has_nil(Type *t) { t = base_type(t); switch (t->kind) { -- cgit v1.2.3 From feacc5cd1176f93fc4b52c081d8ad93ed391df00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 14 Jun 2023 14:03:08 +0100 Subject: Basic enforcement of ordered named arguments/parameters for procedures --- examples/demo/demo.odin | 4 +- src/check_expr.cpp | 131 ++++++++++++++++++++++++++++++++++++++++++++---- src/parser_pos.cpp | 6 ++- 3 files changed, 127 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 4b02bcd53..6863a7768 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1175,13 +1175,13 @@ threading_example :: proc() { N :: 3 pool: thread.Pool - thread.pool_init(pool=&pool, thread_count=N, allocator=context.allocator) + thread.pool_init(pool=&pool, allocator=context.allocator, thread_count=N) defer thread.pool_destroy(&pool) for i in 0..<30 { // be mindful of the allocator used for tasks. The allocator needs to be thread safe, or be owned by the task for exclusive use - thread.pool_add_task(pool=&pool, procedure=task_proc, data=nil, user_index=i, allocator=context.allocator) + thread.pool_add_task(pool=&pool, allocator=context.allocator, procedure=task_proc, data=nil, user_index=i) } thread.pool_start(&pool) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 830b5315d..c6b332cde 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -14,6 +14,7 @@ enum CallArgumentError { CallArgumentError_ParameterMissing, CallArgumentError_DuplicateParameter, CallArgumentError_NoneConstantParameter, + CallArgumentError_OutOfOrderParameters, CallArgumentError_MAX, }; @@ -121,6 +122,7 @@ gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, Stri gb_internal bool is_diverging_expr(Ast *expr); +gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, Slice const &args, bool show_error); enum LoadDirectiveResult { LoadDirective_Success = 0, @@ -5604,6 +5606,10 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } }); + if (check_order_of_call_arguments(c, proc_type, call, ce->args, show_error)) { + return CallArgumentError_OutOfOrderParameters; + } + for_array(i, ce->args) { Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); @@ -5867,6 +5873,99 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco return true; } +gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, Slice const &args, bool show_error) { + CallArgumentError err = CallArgumentError_None; + + if (proc_type == nullptr || !is_type_proc(proc_type)) { + // ignore for the time being + return err; + } + + ast_node(ce, CallExpr, call); + if (!is_call_expr_field_value(ce)) { + return err; + } + + TypeProc *pt = &base_type(proc_type)->Proc; + isize param_count = pt->param_count; + + TEMPORARY_ALLOCATOR_GUARD(); + + auto arg_order_indices = slice_make(temporary_allocator(), args.count); + auto visited = slice_make(temporary_allocator(), param_count); + + for_array(i, args) { + Ast *arg = args[i]; + ast_node(fv, FieldValue, arg); + + Ast *field = fv->field; + String name = {}; + if (field != nullptr && field->kind == Ast_Ident) { + name = field->Ident.token.string; + } else { + err = CallArgumentError_InvalidFieldValue; + if (show_error) { + gbString s = expr_to_string(arg); + error(arg, "Invalid parameter name '%s' in procedure call", s); + gb_string_free(s); + } + } + + isize index = lookup_procedure_parameter(pt, name); + if (index < 0) { + err = CallArgumentError_InvalidFieldValue; + if (show_error) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); + } + } + if (visited[index]) { + err = CallArgumentError_DuplicateParameter; + if (show_error) { + error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); + } + } + arg_order_indices[i] = index; + } + + if (err) { + return err; + } + + for (isize i = 0; i < arg_order_indices.count-1; i++) { + isize a = arg_order_indices[i+0]; + isize b = arg_order_indices[i+1]; + GB_ASSERT(a != b); + if (a > b) { + err = CallArgumentError_OutOfOrderParameters; + if (show_error) { + Ast *arg_a = args[i+0]; + Ast *arg_b = args[i+1]; + + isize curr_a_order = a; + for (isize j = i; j >= 0; j--) { + isize j_order = arg_order_indices[j]; + if (b < j_order && j_order < curr_a_order) { + curr_a_order = j_order; + arg_a = args[j]; + } + } + + + ast_node(fv_a, FieldValue, arg_a); + ast_node(fv_b, FieldValue, arg_b); + + gbString s_a = expr_to_string(fv_a->field); + gbString s_b = expr_to_string(fv_b->field); + error(arg_b, "Parameter names out of order, expected '%s' to be called before '%s'", s_b, s_a); + gb_string_free(s_b); + gb_string_free(s_a); + } + } + } + + return err; +} + gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Slice const &args) { ast_node(ce, CallExpr, call); @@ -5878,17 +5977,6 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op Type *result_type = t_invalid; if (is_call_expr_field_value(ce)) { - call_checker = check_named_call_arguments; - - operands = array_make(heap_allocator(), args.count); - - // NOTE(bill): This is give type hints for the named parameters - // in order to improve the type inference system - - StringMap type_hint_map = {}; // Key: String - string_map_init(&type_hint_map, 2*args.count); - defer (string_map_destroy(&type_hint_map)); - Type *ptype = nullptr; bool single_case = true; @@ -5903,6 +5991,27 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op ptype = proc_type; } + if (check_order_of_call_arguments(c, ptype, call, args, true)) { + CallArgumentData data = {}; + data.result_type = t_invalid; + if (ptype && is_type_proc(ptype) && !is_type_polymorphic(ptype)) { + data.result_type = reduce_tuple_to_single_type(ptype->Proc.results); + } + return data; + } + + call_checker = check_named_call_arguments; + + operands = array_make(heap_allocator(), args.count); + + // NOTE(bill): This is give type hints for the named parameters + // in order to improve the type inference system + + StringMap type_hint_map = {}; // Key: String + string_map_init(&type_hint_map, 2*args.count); + defer (string_map_destroy(&type_hint_map)); + + if (single_case) { Type *bptype = base_type(ptype); if (is_type_proc(bptype)) { diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 52d49e897..2f22a85d3 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -41,7 +41,11 @@ gb_internal Token ast_token(Ast *node) { case Ast_MatrixIndexExpr: return node->MatrixIndexExpr.open; case Ast_SliceExpr: return node->SliceExpr.open; case Ast_Ellipsis: return node->Ellipsis.token; - case Ast_FieldValue: return node->FieldValue.eq; + case Ast_FieldValue: + if (node->FieldValue.field) { + return ast_token(node->FieldValue.field); + } + return node->FieldValue.eq; case Ast_EnumFieldValue: return ast_token(node->EnumFieldValue.name); case Ast_DerefExpr: return node->DerefExpr.op; case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x); -- cgit v1.2.3 From c66ac9725ee89df82b70a1109ee1988360d5ab6d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 14 Jun 2023 14:56:33 +0100 Subject: Separate out logic for checking mixture of named and unnamed parameters --- src/check_expr.cpp | 67 +++++++++++++++++++++++++++++++----------------------- src/parser.cpp | 2 -- 2 files changed, 38 insertions(+), 31 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c6b332cde..d3e287ba4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6849,6 +6849,34 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O +// returns true on failure +gb_internal bool check_call_parameter_mixture(Operand *operand, Slice const &args, char const *context) { + bool failure = false; + if (args.count > 0) { + bool first_is_field_value = (args[0]->kind == Ast_FieldValue); + for (Ast *arg : args) { + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != Ast_FieldValue; + } else { + mix = arg->kind == Ast_FieldValue; + } + if (mix) { + error(arg, "Mixture of 'field = value' and value elements in a %s is not allowed", context); + failure = true; + } + } + + } + return failure; +} + +#define CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(context_) if (check_call_parameter_mixture(operand, args, "procedure call")) { \ + operand->mode = Addressing_Invalid; \ + operand->expr = call; \ + return Expr_Stmt; \ +} + gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && @@ -6888,30 +6916,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - if (args.count > 0) { - bool fail = false; - bool first_is_field_value = (args[0]->kind == Ast_FieldValue); - for (Ast *arg : args) { - bool mix = false; - if (first_is_field_value) { - mix = arg->kind != Ast_FieldValue; - } else { - mix = arg->kind == Ast_FieldValue; - } - if (mix) { - error(arg, "Mixture of 'field = value' and value elements in a procedure call is not allowed"); - fail = true; - } - } - - if (fail) { - operand->mode = Addressing_Invalid; - operand->expr = call; - return Expr_Stmt; - } - } - if (operand->mode == Addressing_Invalid) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call"); for (Ast *arg : args) { if (arg->kind == Ast_FieldValue) { arg = arg->FieldValue.value; @@ -6926,6 +6932,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (operand->mode == Addressing_Type) { Type *t = operand->type; if (is_type_polymorphic_record(t)) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction"); + if (!is_type_named(t)) { gbString s = expr_to_string(operand->expr); error(call, "Illegal use of an unnamed polymorphic record, %s", s); @@ -6951,6 +6959,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c operand->type = t_invalid; } } else { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion"); + operand->mode = Addressing_Invalid; isize arg_count = args.count; switch (arg_count) { @@ -6996,6 +7006,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } if (operand->mode == Addressing_Builtin) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("builtin call"); + i32 id = operand->builtin_id; Entity *e = entity_of_node(operand->expr); if (e != nullptr && e->token.string == "expand_to_tuple") { @@ -7009,6 +7021,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return builtin_procs[id].kind; } + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call"); + Entity *initial_entity = entity_of_node(operand->expr); if (initial_entity != nullptr && initial_entity->kind == Entity_Procedure) { @@ -7095,7 +7109,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (decl->proc_lit) { ast_node(pl, ProcLit, decl->proc_lit); if (pl->inlining == ProcInlining_no_inline) { - error(call, "'inline' cannot be applied to a procedure that has be marked as 'no_inline'"); + error(call, "'#force_inline' cannot be applied to a procedure that has be marked as '#force_no_inline'"); } } } @@ -7108,9 +7122,6 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c operand->expr = call; { - if (proc_type == t_invalid) { - // gb_printf_err("%s\n", expr_to_string(operand->expr)); - } Type *type = nullptr; if (operand->expr != nullptr && operand->expr->kind == Ast_CallExpr) { type = type_of_expr(operand->expr->CallExpr.proc); @@ -7128,8 +7139,6 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - // add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); - return Expr_Expr; } diff --git a/src/parser.cpp b/src/parser.cpp index 883342b21..96b7c96ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2777,8 +2777,6 @@ gb_internal Ast *parse_call_expr(AstFile *f, Ast *operand) { Ast *value = parse_value(f); arg = ast_field_value(f, arg, value, eq); - - } array_add(&args, arg); -- cgit v1.2.3 From 242d3b3c4d7e269b04c96a81dbf6e5f5fbeb5e8b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 14 Jun 2023 15:40:52 +0100 Subject: Begin work allowing mixture of named and unnamed --- src/check_expr.cpp | 73 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 28 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d3e287ba4..52ab5092e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -101,8 +101,7 @@ gb_internal void check_struct_type (CheckerContext *c, Type *st gb_internal void check_union_type (CheckerContext *c, Type *union_type, Ast *node, Array *poly_operands, Type *named_type = nullptr, Type *original_type_for_poly = nullptr); -gb_internal CallArgumentData check_call_arguments (CheckerContext *c, Operand *operand, Type *proc_type, Ast *call); -gb_internal Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name); +gb_internal Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name); gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); @@ -122,7 +121,7 @@ gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, Stri gb_internal bool is_diverging_expr(Ast *expr); -gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, Slice const &args, bool show_error); +gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, bool show_error); enum LoadDirectiveResult { LoadDirective_Success = 0, @@ -5606,7 +5605,7 @@ gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } }); - if (check_order_of_call_arguments(c, proc_type, call, ce->args, show_error)) { + if (check_order_of_call_arguments(c, proc_type, call, show_error)) { return CallArgumentError_OutOfOrderParameters; } @@ -5873,7 +5872,7 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco return true; } -gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, Slice const &args, bool show_error) { +gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, bool show_error) { CallArgumentError err = CallArgumentError_None; if (proc_type == nullptr || !is_type_proc(proc_type)) { @@ -5891,11 +5890,11 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T TEMPORARY_ALLOCATOR_GUARD(); - auto arg_order_indices = slice_make(temporary_allocator(), args.count); + auto arg_order_indices = slice_make(temporary_allocator(), ce->args.count); auto visited = slice_make(temporary_allocator(), param_count); - for_array(i, args) { - Ast *arg = args[i]; + for_array(i, ce->args) { + Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); Ast *field = fv->field; @@ -5938,15 +5937,15 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T if (a > b) { err = CallArgumentError_OutOfOrderParameters; if (show_error) { - Ast *arg_a = args[i+0]; - Ast *arg_b = args[i+1]; + Ast *arg_a = ce->args[i+0]; + Ast *arg_b = ce->args[i+1]; isize curr_a_order = a; for (isize j = i; j >= 0; j--) { isize j_order = arg_order_indices[j]; if (b < j_order && j_order < curr_a_order) { curr_a_order = j_order; - arg_a = args[j]; + arg_a = ce->args[j]; } } @@ -5967,15 +5966,18 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T } -gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Slice const &args) { +gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Ast *call) { ast_node(ce, CallExpr, call); CallArgumentCheckerType *call_checker = check_call_arguments_internal; Array operands = {}; defer (array_free(&operands)); + Type *result_type = t_invalid; + Type *proc_type = base_type(operand->type); + Slice const &args = ce->args; if (is_call_expr_field_value(ce)) { Type *ptype = nullptr; bool single_case = true; @@ -5991,7 +5993,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op ptype = proc_type; } - if (check_order_of_call_arguments(c, ptype, call, args, true)) { + if (check_order_of_call_arguments(c, ptype, call, true)) { CallArgumentData data = {}; data.result_type = t_invalid; if (ptype && is_type_proc(ptype) && !is_type_polymorphic(ptype)) { @@ -6850,20 +6852,31 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O // returns true on failure -gb_internal bool check_call_parameter_mixture(Operand *operand, Slice const &args, char const *context) { +gb_internal bool check_call_parameter_mixture(Operand *operand, Slice const &args, char const *context, bool allow_mixed=false) { bool failure = false; if (args.count > 0) { - bool first_is_field_value = (args[0]->kind == Ast_FieldValue); - for (Ast *arg : args) { - bool mix = false; - if (first_is_field_value) { - mix = arg->kind != Ast_FieldValue; - } else { - mix = arg->kind == Ast_FieldValue; + if (allow_mixed) { + bool was_named = false; + for (Ast *arg : args) { + if (was_named && arg->kind != Ast_FieldValue) { + error(arg, "Non-named parameter is not allowed to follow named parameter i.e. 'field = value' in a %s", context); + failure = true; + } + was_named = was_named || arg->kind == Ast_FieldValue; } - if (mix) { - error(arg, "Mixture of 'field = value' and value elements in a %s is not allowed", context); - failure = true; + } else { + bool first_is_field_value = (args[0]->kind == Ast_FieldValue); + for (Ast *arg : args) { + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != Ast_FieldValue; + } else { + mix = arg->kind == Ast_FieldValue; + } + if (mix) { + error(arg, "Mixture of 'field = value' and value elements in a %s is not allowed", context); + failure = true; + } } } @@ -6871,7 +6884,7 @@ gb_internal bool check_call_parameter_mixture(Operand *operand, Slice con return failure; } -#define CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(context_) if (check_call_parameter_mixture(operand, args, "procedure call")) { \ +#define CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(context_, ...) if (check_call_parameter_mixture(operand, args, context_, ##__VA_ARGS__)) { \ operand->mode = Addressing_Invalid; \ operand->expr = call; \ return Expr_Stmt; \ @@ -7021,6 +7034,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return builtin_procs[id].kind; } + // CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call", true); CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call"); Entity *initial_entity = entity_of_node(operand->expr); @@ -7034,8 +7048,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - Type *proc_type = base_type(operand->type); if (operand->mode != Addressing_ProcGroup) { + Type *proc_type = base_type(operand->type); bool valid_type = (proc_type != nullptr) && is_type_proc(proc_type); bool valid_mode = is_operand_value(*operand); if (!valid_type || !valid_mode) { @@ -7053,7 +7067,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - CallArgumentData data = check_call_arguments(c, operand, proc_type, call, args); + CallArgumentData data = check_call_arguments(c, operand, call); Type *result_type = data.result_type; gb_zero_item(operand); operand->expr = call; @@ -7064,7 +7078,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return Expr_Stmt; } - Type *pt = base_type(proc_type); + Type *pt = base_type(operand->type); + if (pt == nullptr) { + pt = t_invalid; + } if (pt == t_invalid) { if (operand->expr != nullptr && operand->expr->kind == Ast_CallExpr) { pt = type_of_expr(operand->expr->CallExpr.proc); -- cgit v1.2.3 From 2992ca5df122e2f20113d5b357413c7fff606879 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 15 Jun 2023 01:37:55 +0100 Subject: Basic support for new procedure code (non-polymorphic, non-proc-group) --- src/check_expr.cpp | 388 ++++++++++++++++++++++++++++++++++++++++++++-- src/llvm_backend_proc.cpp | 119 ++++++++++++++ src/parser.hpp | 6 + src/parser_pos.cpp | 6 +- 4 files changed, 501 insertions(+), 18 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 52ab5092e..cc3f268c3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -123,6 +123,8 @@ gb_internal bool is_diverging_expr(Ast *expr); gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, bool show_error); +gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -5151,14 +5153,19 @@ enum UnpackFlag : u32 { }; -gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, UnpackFlags flags) { +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs_arguments, UnpackFlags flags) { bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; bool optional_ok = false; isize tuple_index = 0; - for_array(i, rhs) { + for (Ast *rhs : rhs_arguments) { + if (rhs->kind == Ast_FieldValue) { + error(rhs, "Invalid use of 'field = value'"); + rhs = rhs->FieldValue.value; + } + CheckerContext c_ = *ctx; CheckerContext *c = &c_; @@ -5166,12 +5173,11 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize Type *type_hint = nullptr; + if (lhs != nullptr && tuple_index < lhs_count) { // NOTE(bill): override DeclInfo for dependency Entity *e = lhs[tuple_index]; if (e != nullptr) { - // DeclInfo *decl = decl_info_of_entity(e); - // if (decl) c->decl = decl; type_hint = e->type; if (e->flags & EntityFlag_Ellipsis) { GB_ASSERT(is_type_slice(e->type)); @@ -5183,8 +5189,6 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize // NOTE(bill): override DeclInfo for dependency Entity *e = lhs[lhs_count-1]; if (e != nullptr) { - // DeclInfo *decl = decl_info_of_entity(e); - // if (decl) c->decl = decl; type_hint = e->type; if (e->flags & EntityFlag_Ellipsis) { GB_ASSERT(is_type_slice(e->type)); @@ -5194,15 +5198,15 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } } - Ast *rhs_expr = unparen_expr(rhs[i]); + Ast *rhs_expr = unparen_expr(rhs); if (allow_undef && rhs_expr != nullptr && rhs_expr->kind == Ast_Uninit) { // NOTE(bill): Just handle this very specific logic here o.type = t_untyped_uninit; o.mode = Addressing_Value; - o.expr = rhs[i]; - add_type_and_value(c, rhs[i], o.mode, o.type, o.value); + o.expr = rhs; + add_type_and_value(c, rhs, o.mode, o.type, o.value); } else { - check_expr_base(c, &o, rhs[i], type_hint); + check_expr_base(c, &o, rhs, type_hint); } if (o.mode == Addressing_NoValue) { error_operand_no_value(&o); @@ -5210,7 +5214,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } if (o.type == nullptr || o.type->kind != Type_Tuple) { - if (allow_ok && lhs_count == 2 && rhs.count == 1 && + if (allow_ok && lhs_count == 2 && rhs_arguments.count == 1 && (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk || o.mode == Addressing_OptionalOkPtr)) { Ast *expr = unparen_expr(o.expr); @@ -5966,14 +5970,364 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T } +gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContext *c, Operand *operand, Ast *call) { + Type *proc_type = nullptr; + + CallArgumentData data = {}; + data.result_type = t_invalid; + + + GB_ASSERT(operand->mode != Addressing_ProcGroup); + + proc_type = base_type(operand->type); + + if (proc_type == nullptr || proc_type->kind != Type_Proc) { + gbString s = type_to_string(proc_type); + error(call, "Expected a procedure to call, got %s", s); + gb_string_free(s); + + return data; + } + + if (is_type_polymorphic(proc_type)) { + error(call, "Polymorphic procedures not yet supported"); + return data; + } + + TypeProc *pt = &proc_type->Proc; + + TEMPORARY_ALLOCATOR_GUARD(); + ast_node(ce, CallExpr, call); + + bool any_failure = false; + + bool vari_expand = (ce->ellipsis.pos.line != 0); + + auto positional_args = ce->args; + for (isize i = 0; i < ce->args.count; i++) { + Ast *arg = ce->args.data[i]; + if (arg->kind == Ast_FieldValue) { + positional_args.count = i; + break; + } + } + auto named_args = slice(ce->args, positional_args.count, ce->args.count); + + auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); + auto variadic_operands = array_make(heap_allocator(), 0, 0); + + defer (array_free(&positional_operands)); + defer (array_free(&variadic_operands)); + + isize positional_operand_count = 0; + + auto visited = slice_make(temporary_allocator(), pt->param_count); + + if (positional_args.count > 0) { + isize lhs_count = -1; + bool is_variadic = false; + Entity **lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + + if (!is_variadic) { + if (pt->param_count < positional_operands.count) { + char const *err_fmt = "Too many arguments for '%s', expected a maximum of %td arguments, got %td"; + gbString c = expr_to_string(ce->proc); + error(call, err_fmt, c, pt->param_count, positional_operands.count); + gb_string_free(c); + return data; + } + } + + for (Operand const &o : positional_operands) { + check_no_copy_assignment(o, str_lit("procedure call expression")); + } + + positional_operand_count = gb_min(pt->param_count, positional_operands.count); + if (is_variadic) { + positional_operand_count = gb_min(pt->variadic_index, positional_operand_count); + } + + for (isize i = 0; i < positional_operand_count; i++) { + visited[i] = true; + } + if (is_variadic) { + visited[pt->variadic_index] = true; + } + + for (isize i = positional_operand_count; i < positional_operands.count; i++) { + array_add(&variadic_operands, positional_operands[i]); + } + if (vari_expand) { + if (variadic_operands.count > 1) { + error(variadic_operands[1].expr, "Unexpected position arguments after variadic expansion with '..'"); + return data; + } + } + + array_resize(&positional_operands, positional_operand_count); + } + + isize param_count = 0; + isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); + + if (named_args.count == 0 && positional_operand_count < param_count_excluding_defaults) { + char const *err_fmt = "Too few arguments for '%s', expected a minimum of %td arguments, got %td"; + gbString c = expr_to_string(ce->proc); + error(call, err_fmt, c, param_count_excluding_defaults, positional_operands.count); + gb_string_free(c); + return data; + } + + for_array(i, positional_operands) { + Operand &o = positional_operands[i]; + isize param_index = i; + + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); + + check_assignment(c, &o, e->type, str_lit("procedure call expression")); + } + + if (pt->variadic) { + isize param_index = pt->variadic_index; + + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); + GB_ASSERT(e->flags & EntityFlag_Ellipsis); + GB_ASSERT(is_type_slice(e->type)); + + if (vari_expand) { + if (variadic_operands.count != 0) { + GB_ASSERT(variadic_operands.count == 1); + check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); + } + } else { + Type *elem = e->type->Slice.elem; + for (Operand &o : variadic_operands) { + check_assignment(c, &o, elem, str_lit("procedure call expression")); + } + } + } + + array_resize(&positional_operands, pt->param_count); + + for_array(i, named_args) { + Ast *arg = named_args[i]; + if (arg->kind != Ast_FieldValue) { + error(arg, "Expected a 'field = value'"); + return data; + } + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + any_failure = true; + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; + isize param_index = lookup_procedure_parameter(pt, name); + if (param_index < 0) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); + any_failure = true; + continue; + } + + bool prev_visited = visited[param_index]; + visited[param_index] = true; + + if (prev_visited) { + error(arg, "Duplicate parameter named '%.*s' in procedure call", LIT(name)); + } + + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); + + Operand o = {}; + check_expr_with_type_hint(c, &o, fv->value, e->type); + if (o.mode == Addressing_Invalid) { + any_failure = true; + } + + check_assignment(c, &o, e->type, str_lit("procedure call expression")); + check_no_copy_assignment(o, str_lit("procedure call expression")); + + if (!prev_visited) { + positional_operands[param_index] = o; + } + } + + for_array(i, visited) { + if (!visited[i]) { + if (pt->variadic && i == pt->variadic_index) { + visited[i] = true; + continue; + } + + Entity *e = pt->params->Tuple.variables[i]; + if (e->kind == Entity_Variable) { + if (has_parameter_value(e->Variable.param_value)) { + visited[i] = true; + continue; + } + } + gbString t = type_to_string(e->type); + error(call, "Missing parameter of type '%s' at index %td", t, i); + gb_string_free(t); + } + } + + if (any_failure) { + return data; + } + + + auto ordered_args = gb_alloc_item(permanent_allocator(), AstOrderedArgs); + ordered_args->positional = positional_args; + ordered_args->named = named_args; + + ce->ordered_args = ordered_args; + + data.result_type = pt->results; + return data; +#if 0 + + + + /* + auto visited = slice_make(temporary_allocator(), pt->param_count); + auto ordered_values = slice_make(temporary_allocator(), pt->param_count); + + + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + + isize param_index = i; + String param_name = {}; + + if (arg->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + any_failure = true; + gb_string_free(expr_str); + continue; + } + param_name = fv->field->Ident.token.string; + param_index = lookup_procedure_parameter(pt, param_name); + if (param_index < 0) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(param_name)); + any_failure = true; + continue; + } + arg = fv->value; + } else { + if (param_index >= pt->param_count) { + error(arg, "Too many parameters in procedure call, expected a maximum of %td, got %td", pt->param_count, ce->args.count); + any_failure = true; + break; + } + + param_name = pt->params->Tuple.variables[param_index]->token.string; + } + if (visited[param_index]) { + error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(param_name)); + any_failure = true; + } else { + ParameterValue value = {}; + value.kind = ParameterValue_Value; + value.original_ast_expr = arg; + value.ast_value = arg; + ordered_values[param_index] = value; + } + visited[param_index] = true; + } + + for (isize i = 0; i < pt->param_count; i++) { + if (!visited[i]) { + Entity *e = pt->params->Tuple.variables[i]; + if (e->kind == Entity_Variable && + has_parameter_value(e->Variable.param_value)) { + ordered_values[i] = e->Variable.param_value; + visited[i] = true; + } + } + } + + for (isize i = 0; i < visited.count; i++) { + if (!visited[i]) { + Entity *e = pt->params->Tuple.variables[i]; + gbString t = type_to_string(e->type); + defer (gb_string_free(t)); + if (is_blank_ident(e->token)) { + error(call, "Missing parameter of type '%s' at index %td", t, i); + } else { + error(call, "Missing parameter '%.*s' of type '%s'", LIT(e->token.string), t, i); + } + return data; + } + } + */ + if (any_failure) { + return data; + } + + error(call, "TODO: Implement check_call_arguments_single_procedure for %s", type_to_string(proc_type)); + + Array operands = {}; + defer (array_free(&operands)); + + Ast *ident = unparen_expr(operand->expr); + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = unparen_expr(s); + } + + Entity *e = entity_of_node(ident); + + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); + gb_unused(err); + Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; + add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + } + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + CheckerContext ctx = *c; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } + } + return data; +#endif +} + + gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Ast *call) { + if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) { + return check_call_arguments_single_procedure(c, operand, call); + } + ast_node(ce, CallExpr, call); CallArgumentCheckerType *call_checker = check_call_arguments_internal; Array operands = {}; defer (array_free(&operands)); - Type *result_type = t_invalid; Type *proc_type = base_type(operand->type); @@ -6102,7 +6456,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } for (Operand const &o : operands) { - check_no_copy_assignment(o, str_lit("call expression")); + check_no_copy_assignment(o, str_lit("procedure call expression")); } if (operand->mode == Addressing_ProcGroup) { @@ -6861,6 +7215,7 @@ gb_internal bool check_call_parameter_mixture(Operand *operand, Slice con if (was_named && arg->kind != Ast_FieldValue) { error(arg, "Non-named parameter is not allowed to follow named parameter i.e. 'field = value' in a %s", context); failure = true; + break; } was_named = was_named || arg->kind == Ast_FieldValue; } @@ -7034,8 +7389,11 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return builtin_procs[id].kind; } - // CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call", true); - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call"); + if (operand->mode == Addressing_ProcGroup) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure group call"); + } else { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call", true); + } Entity *initial_entity = entity_of_node(operand->expr); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 8b9f8b249..3c1cfe47c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3145,6 +3145,118 @@ gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { } return res; } + +gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lbValue value) { + if (is_type_tuple(value.type)) { + for_array(i, value.type->Tuple.variables) { + lbValue sub_value = lb_emit_struct_ev(p, value, cast(i32)i); + array_add(args, sub_value); + } + } else { + array_add(args, value); + } +} +gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstOrderedArgs *ordered_args) { + ast_node(ce, CallExpr, call); + + auto args = array_make(permanent_allocator(), 0, pt->param_count); + + bool vari_expand = (ce->ellipsis.pos.line != 0); + + for_array(i, ordered_args->positional) { + Entity *e = pt->params->Tuple.variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + + if (pt->variadic && pt->variadic_index == i) { + lbValue variadic_args = lb_const_nil(p->module, e->type); + auto variadic = slice(ordered_args->positional, pt->variadic_index, ordered_args->positional.count); + if (variadic.count != 0) { + // variadic call argument generation + Type *slice_type = e->type; + GB_ASSERT(slice_type->kind == Type_Slice); + if (vari_expand) { + GB_ASSERT(variadic.count == 1); + variadic_args = lb_build_expr(p, variadic[0]); + variadic_args = lb_emit_conv(p, variadic_args, slice_type); + } else { + Type *elem_type = slice_type->Slice.elem; + + auto var_args = array_make(heap_allocator(), 0, variadic.count); + defer (array_free(&var_args)); + for (Ast *var_arg : variadic) { + lbValue v = lb_build_expr(p, var_arg); + lb_add_values_to_array(p, &var_args, v); + } + isize slice_len = var_args.count; + if (slice_len > 0) { + lbAddr slice = lb_add_local_generated(p, slice_type, true); + lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + + for (isize i = 0; i < var_args.count; i++) { + lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i); + lbValue var_arg = var_args[i]; + var_arg = lb_emit_conv(p, var_arg, elem_type); + lb_emit_store(p, addr, var_arg); + } + + lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0); + lbValue len = lb_const_int(p->module, t_int, slice_len); + lb_fill_slice(p, slice, base_elem, len); + + variadic_args = lb_addr_load(p, slice); + } + } + } + array_add(&args, variadic_args); + + break; + } else { + lbValue value = lb_build_expr(p, ordered_args->positional[i]); + lb_add_values_to_array(p, &args, value); + } + } + + array_resize(&args, pt->param_count); + + for (Ast *arg : ordered_args->named) { + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + gb_unused(name); + isize param_index = lookup_procedure_parameter(pt, name); + GB_ASSERT(param_index >= 0); + + lbValue value = lb_build_expr(p, fv->value); + GB_ASSERT(!is_type_tuple(value.type)); + args[param_index] = value; + } + + TokenPos pos = ast_token(ce->proc).pos; + + for_array(i, args) { + Entity *e = pt->params->Tuple.variables[i]; + lbValue arg = args[i]; + if (arg.value == nullptr) { + switch (e->kind) { + case Entity_TypeName: + args[i] = lb_const_nil(p->module, e->type); + break; + case Entity_Variable: + args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); + break; + case Entity_Constant: + GB_PANIC("TODO constant parameter"); + break; + } + } else { + args[i] = lb_emit_conv(p, arg, e->type); + } + } + + + return lb_emit_call(p, value, args, ce->inlining); +} + gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -3219,6 +3331,10 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; + if (ce->ordered_args) { + return lb_build_call_expr_internal_with_arg_ordered_args(p, value, pt, expr, ce->ordered_args); + } + if (is_call_expr_field_value(ce)) { auto args = array_make(permanent_allocator(), pt->param_count); @@ -3274,6 +3390,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { isize arg_count = 0; for_array(i, ce->args) { Ast *arg = ce->args[i]; + if (arg->kind == Ast_FieldValue) { + arg = arg->FieldValue.value; + } TypeAndValue tav = type_and_value_of_expr(arg); GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode); GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg)); diff --git a/src/parser.hpp b/src/parser.hpp index 6ba4ef6d6..e0e78fa1d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -367,6 +367,11 @@ gb_global char const *union_type_kind_strings[UnionType_COUNT] = { "#shared_nil", }; +struct AstOrderedArgs { + Slice positional; + Slice named; +}; + #define AST_KINDS \ AST_KIND(Ident, "identifier", struct { \ Token token; \ @@ -442,6 +447,7 @@ AST_KIND(_ExprBegin, "", bool) \ ProcInlining inlining; \ bool optional_ok_one; \ bool was_selector; \ + AstOrderedArgs *ordered_args; \ }) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(EnumFieldValue, "enum field value", struct { \ diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index 2f22a85d3..3d2e8f27d 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -37,9 +37,9 @@ gb_internal Token ast_token(Ast *node) { return ast_token(node->ImplicitSelectorExpr.selector); } return node->ImplicitSelectorExpr.token; - case Ast_IndexExpr: return node->IndexExpr.open; - case Ast_MatrixIndexExpr: return node->MatrixIndexExpr.open; - case Ast_SliceExpr: return node->SliceExpr.open; + case Ast_IndexExpr: return ast_token(node->IndexExpr.expr); + case Ast_MatrixIndexExpr: return ast_token(node->MatrixIndexExpr.expr); + case Ast_SliceExpr: return ast_token(node->SliceExpr.expr); case Ast_Ellipsis: return node->Ellipsis.token; case Ast_FieldValue: if (node->FieldValue.field) { -- cgit v1.2.3 From 427f212170114b006fcb6ff1366231f99acff13e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Jun 2023 13:56:00 +0100 Subject: Begin work in procedure calls --- src/check_expr.cpp | 333 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 227 insertions(+), 106 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc3f268c3..c3f6002c7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5976,11 +5976,17 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex CallArgumentData data = {}; data.result_type = t_invalid; - - GB_ASSERT(operand->mode != Addressing_ProcGroup); - proc_type = base_type(operand->type); + if (operand->mode == Addressing_ProcGroup) { + Array procs = proc_group_entities(c, *operand); + if (procs.count == 1) { + proc_type = base_type(procs[0]->type); + } else { + error(call, "Procedure groups >1 not yet supported"); + return data; + } + } if (proc_type == nullptr || proc_type->kind != Type_Proc) { gbString s = type_to_string(proc_type); error(call, "Expected a procedure to call, got %s", s); @@ -5989,12 +5995,15 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex return data; } - if (is_type_polymorphic(proc_type)) { + if (proc_type != nullptr && is_type_polymorphic(proc_type)) { error(call, "Polymorphic procedures not yet supported"); return data; } - TypeProc *pt = &proc_type->Proc; + TypeProc *pt = nullptr; + if (proc_type) { + pt = &proc_type->Proc; + } TEMPORARY_ALLOCATOR_GUARD(); ast_node(ce, CallExpr, call); @@ -6015,21 +6024,31 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); auto variadic_operands = array_make(heap_allocator(), 0, 0); + auto named_operands = array_make(heap_allocator(), 0, 0); defer (array_free(&positional_operands)); defer (array_free(&variadic_operands)); + defer (array_free(&named_operands)); isize positional_operand_count = 0; - auto visited = slice_make(temporary_allocator(), pt->param_count); + Slice visited = {}; if (positional_args.count > 0) { isize lhs_count = -1; bool is_variadic = false; - Entity **lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + Entity **lhs = nullptr; + if (proc_type != nullptr && is_type_proc(proc_type)) { + lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + } + positional_operand_count = positional_operands.count; - if (!is_variadic) { + if (proc_type != nullptr) { + visited = slice_make(temporary_allocator(), pt->param_count); + + if (!pt->variadic) { if (pt->param_count < positional_operands.count) { char const *err_fmt = "Too many arguments for '%s', expected a maximum of %td arguments, got %td"; gbString c = expr_to_string(ce->proc); @@ -6037,27 +6056,24 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex gb_string_free(c); return data; } - } - - for (Operand const &o : positional_operands) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } + positional_operand_count = positional_operands.count; + } else { + // only state it is visited if it was set later on + visited[pt->variadic_index] = positional_operand_count > pt->variadic_index; - positional_operand_count = gb_min(pt->param_count, positional_operands.count); - if (is_variadic) { positional_operand_count = gb_min(pt->variadic_index, positional_operand_count); } + for (isize i = 0; i < positional_operand_count; i++) { visited[i] = true; } - if (is_variadic) { - visited[pt->variadic_index] = true; - } for (isize i = positional_operand_count; i < positional_operands.count; i++) { array_add(&variadic_operands, positional_operands[i]); } + array_resize(&positional_operands, positional_operand_count); + if (vari_expand) { if (variadic_operands.count > 1) { error(variadic_operands[1].expr, "Unexpected position arguments after variadic expansion with '..'"); @@ -6065,119 +6081,214 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex } } - array_resize(&positional_operands, positional_operand_count); - } + isize param_count = 0; + isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); - isize param_count = 0; - isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); + if (named_args.count == 0 && positional_operands.count < param_count_excluding_defaults) { + char const *err_fmt = "Too few arguments for '%s', expected a minimum of %td arguments, got %td"; + gbString c = expr_to_string(ce->proc); + error(call, err_fmt, c, param_count_excluding_defaults, positional_operands.count); + gb_string_free(c); + return data; + } - if (named_args.count == 0 && positional_operand_count < param_count_excluding_defaults) { - char const *err_fmt = "Too few arguments for '%s', expected a minimum of %td arguments, got %td"; - gbString c = expr_to_string(ce->proc); - error(call, err_fmt, c, param_count_excluding_defaults, positional_operands.count); - gb_string_free(c); - return data; - } - for_array(i, positional_operands) { - Operand &o = positional_operands[i]; - isize param_index = i; + for_array(i, positional_operands) { + Operand &o = positional_operands[i]; + isize param_index = i; - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); - check_assignment(c, &o, e->type, str_lit("procedure call expression")); - } + check_assignment(c, &o, e->type, str_lit("procedure call expression")); + } - if (pt->variadic) { - isize param_index = pt->variadic_index; + if (pt->variadic) { + isize param_index = pt->variadic_index; - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); - GB_ASSERT(e->flags & EntityFlag_Ellipsis); - GB_ASSERT(is_type_slice(e->type)); + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); + GB_ASSERT(e->flags & EntityFlag_Ellipsis); + GB_ASSERT(is_type_slice(e->type)); - if (vari_expand) { - if (variadic_operands.count != 0) { - GB_ASSERT(variadic_operands.count == 1); - check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); - } - } else { - Type *elem = e->type->Slice.elem; - for (Operand &o : variadic_operands) { - check_assignment(c, &o, elem, str_lit("procedure call expression")); + if (vari_expand) { + if (variadic_operands.count != 0) { + GB_ASSERT(variadic_operands.count == 1); + check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); + } + } else { + Type *elem = e->type->Slice.elem; + for (Operand &o : variadic_operands) { + check_assignment(c, &o, elem, str_lit("procedure call expression")); + } } } + + array_resize(&positional_operands, pt->param_count); + } - array_resize(&positional_operands, pt->param_count); - for_array(i, named_args) { - Ast *arg = named_args[i]; - if (arg->kind != Ast_FieldValue) { - error(arg, "Expected a 'field = value'"); - return data; - } - ast_node(fv, FieldValue, arg); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(arg, "Invalid parameter name '%s' in procedure call", expr_str); - any_failure = true; - gb_string_free(expr_str); - continue; - } - String name = fv->field->Ident.token.string; - isize param_index = lookup_procedure_parameter(pt, name); - if (param_index < 0) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); - any_failure = true; - continue; - } + if (named_args.count > 0) { + struct NamedParameter { + String key; + Ast * value; + }; - bool prev_visited = visited[param_index]; - visited[param_index] = true; + auto named_parameters = array_make(heap_allocator(), 0, named_args.count); + defer (array_free(&named_parameters)); + + for_array(i, named_args) { + Ast *arg = named_args[i]; + if (arg->kind != Ast_FieldValue) { + error(arg, "Expected a 'field = value'"); + return data; + } + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + any_failure = true; + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; - if (prev_visited) { - error(arg, "Duplicate parameter named '%.*s' in procedure call", LIT(name)); + array_add(&named_parameters, NamedParameter{name, fv->value}); } - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); + StringMap type_hint_map = {}; // Key: String + string_map_init(&type_hint_map, 2*named_args.count); + defer (string_map_destroy(&type_hint_map)); - Operand o = {}; - check_expr_with_type_hint(c, &o, fv->value, e->type); - if (o.mode == Addressing_Invalid) { - any_failure = true; + if (proc_type != nullptr) { + TypeTuple *param_tuple = &pt->params->Tuple; + for (Entity *e : param_tuple->variables) { + if (is_blank_ident(e->token)) { + continue; + } + string_map_set(&type_hint_map, e->token.string, e->type); + } + } else if (operand->mode == Addressing_ProcGroup) { + Array procs = proc_group_entities(c, *operand); + for (Entity *proc : procs) { + Type *proc_type = base_type(proc->type); + if (is_type_proc(proc_type)) { + TypeProc *pt = &proc_type->Proc; + TypeTuple *param_tuple = nullptr; + if (pt->params != nullptr) { + param_tuple = &pt->params->Tuple; + } + if (param_tuple == nullptr) { + continue; + } + for (Entity *e : param_tuple->variables) { + if (is_blank_ident(e->token)) { + continue; + } + StringHashKey key = string_hash_string(e->token.string); + Type **found = string_map_get(&type_hint_map, key); + if (found) { + Type *t = *found; + if (t == nullptr) { + // NOTE(bill): Ambiguous named parameter across all types + continue; + } + if (are_types_identical(t, e->type)) { + // NOTE(bill): No need to set again + } else { + // NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr + string_map_set(&type_hint_map, key, cast(Type *)nullptr); + } + } else { + string_map_set(&type_hint_map, key, e->type); + } + } + } + } } - check_assignment(c, &o, e->type, str_lit("procedure call expression")); - check_no_copy_assignment(o, str_lit("procedure call expression")); + for (NamedParameter ¶m : named_parameters) { + Type *type_hint = nullptr; + if (Type **found = string_map_get(&type_hint_map, param.key)) { + type_hint = *found; + } - if (!prev_visited) { - positional_operands[param_index] = o; + Operand operand = {}; + check_expr_or_type(c, &operand, param.value, type_hint); + array_add(&named_operands, operand); } - } - for_array(i, visited) { - if (!visited[i]) { - if (pt->variadic && i == pt->variadic_index) { - visited[i] = true; + for (NamedParameter const ¶m : named_parameters) { + isize param_index = lookup_procedure_parameter(pt, param.key); + if (param_index < 0) { + error(param.value, "No parameter named '%.*s' for this procedure type", LIT(param.key)); + any_failure = true; continue; } - Entity *e = pt->params->Tuple.variables[i]; - if (e->kind == Entity_Variable) { - if (has_parameter_value(e->Variable.param_value)) { + bool prev_visited = visited[param_index]; + visited[param_index] = true; + + if (prev_visited) { + error(param.value, "Duplicate parameter named '%.*s' in procedure call", LIT(param.key)); + } + + Entity *e = pt->params->Tuple.variables[param_index]; + GB_ASSERT(e->kind == Entity_Variable); + + Operand o = {}; + check_expr_with_type_hint(c, &o, param.value, e->type); + if (o.mode == Addressing_Invalid) { + any_failure = true; + } + + check_assignment(c, &o, e->type, str_lit("procedure call expression")); + + if (!prev_visited) { + positional_operands[param_index] = o; + } + } + + } + + if (proc_type != nullptr) { + if (pt->variadic) { + visited[pt->variadic_index] = true; + } + + for_array(i, visited) { + if (!visited[i]) { + if (pt->variadic && i == pt->variadic_index) { visited[i] = true; continue; } + + Entity *e = pt->params->Tuple.variables[i]; + if (e->kind == Entity_Variable) { + if (has_parameter_value(e->Variable.param_value)) { + visited[i] = true; + continue; + } + } + gbString t = type_to_string(e->type); + error(call, "Missing parameter of type '%s' at index %td", t, i); + gb_string_free(t); } - gbString t = type_to_string(e->type); - error(call, "Missing parameter of type '%s' at index %td", t, i); - gb_string_free(t); } } + for (Operand const &o : positional_operands) { + check_no_copy_assignment(o, str_lit("procedure call expression")); + } + for (Operand const &o : variadic_operands) { + check_no_copy_assignment(o, str_lit("procedure call expression")); + } + for (Operand const &o : named_operands) { + check_no_copy_assignment(o, str_lit("procedure call expression")); + } + + if (any_failure) { return data; } @@ -6189,7 +6300,9 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex ce->ordered_args = ordered_args; - data.result_type = pt->results; + if (proc_type != nullptr) { + data.result_type = pt->results; + } return data; #if 0 @@ -6274,8 +6387,6 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex return data; } - error(call, "TODO: Implement check_call_arguments_single_procedure for %s", type_to_string(proc_type)); - Array operands = {}; defer (array_free(&operands)); @@ -6318,6 +6429,20 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Ast *call) { + if (operand->mode == Addressing_ProcGroup) { + Array procs = proc_group_entities(c, *operand); + bool all_non_poly = true; + for (Entity *e : procs) { + if (is_type_polymorphic(e->type)) { + all_non_poly = false; + break; + } + } + if (all_non_poly && (procs.count == 1 || c->pkg->name == "bug")) { + return check_call_arguments_single_procedure(c, operand, call); + } + } + if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) { return check_call_arguments_single_procedure(c, operand, call); } @@ -7389,11 +7514,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c return builtin_procs[id].kind; } - if (operand->mode == Addressing_ProcGroup) { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure group call"); - } else { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("procedure call", true); - } + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(operand->mode == Addressing_ProcGroup ? "procedure group call": "procedure call", true); Entity *initial_entity = entity_of_node(operand->expr); -- cgit v1.2.3 From 6568625dea679b4622024f62fc14725aa49b2106 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Jun 2023 22:12:47 +0100 Subject: Fix line error printing for error messages --- src/array.cpp | 4 +- src/check_expr.cpp | 750 ++++++++++++++++++++++++++++++++++++++++++---- src/error.cpp | 31 +- src/gb/gb.h | 39 ++- src/llvm_backend_proc.cpp | 14 +- src/parser.hpp | 4 +- src/types.cpp | 6 + 7 files changed, 765 insertions(+), 83 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/array.cpp b/src/array.cpp index f1a1f93e2..d8e25d25d 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -80,7 +80,9 @@ gb_internal Slice slice_make(gbAllocator const &allocator, isize count) { GB_ASSERT(count >= 0); Slice s = {}; s.data = gb_alloc_array(allocator, T, count); - GB_ASSERT(s.data != nullptr); + if (count > 0) { + GB_ASSERT(s.data != nullptr); + } s.count = count; return s; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c3f6002c7..e0c6be1d1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -66,7 +66,7 @@ gb_internal int valid_index_and_score_cmp(void const *a, void const *b) { -#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); @@ -5314,7 +5314,24 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize * } +gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { + isize param_count = pt->param_count; + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->params->Tuple.variables[i]; + String name = e->token.string; + if (is_blank_ident(name)) { + continue; + } + if (name == parameter_name) { + return i; + } + } + return -1; +} + gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { + CallArgumentError err = CallArgumentError_None; + ast_node(ce, CallExpr, call); GB_ASSERT(is_type_proc(proc_type)); proc_type = base_type(proc_type); @@ -5327,6 +5344,52 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { i64 score = 0; bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + auto ordered_operands = array_make(temporary_allocator(), pt->param_count); + bool *visited = gb_alloc_array(temporary_allocator(), bool, pt->param_count); + + if (ce->split_args) { + GB_ASSERT(ce->split_args->named.count == named_operands.count); + for_array(i, ce->split_args->named) { + Ast *arg = ce->split_args->named[i]; + Operand operand = named_operands[i]; + + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + gb_string_free(expr_str); + } + err = CallArgumentError_InvalidFieldValue; + continue; + } + String name = fv->field->Ident.token.string; + isize param_index = lookup_procedure_parameter(pt, name); + if (param_index < 0) { + if (show_error) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); + } + err = CallArgumentError_ParameterNotFound; + continue; + } + if (visited[param_index]) { + if (show_error) { + error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); + } + err = CallArgumentError_DuplicateParameter; + continue; + } + + visited[param_index] = true; + ordered_operands[param_index] = operand; + + err = CallArgumentError_DuplicateParameter; + } + if (err) { + return err; + } + } + TypeTuple *param_tuple = nullptr; if (pt->params != nullptr) { @@ -5334,7 +5397,6 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } - CallArgumentError err = CallArgumentError_None; Type *final_proc_type = proc_type; Entity *gen_entity = nullptr; @@ -5571,21 +5633,6 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { return ce->args[0]->kind == Ast_FieldValue; } -gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { - isize param_count = pt->param_count; - for (isize i = 0; i < param_count; i++) { - Entity *e = pt->params->Tuple.variables[i]; - String name = e->token.string; - if (is_blank_ident(name)) { - continue; - } - if (name == parameter_name) { - return i; - } - } - return -1; -} - gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { ast_node(ce, CallExpr, call); GB_ASSERT(is_type_proc(proc_type)); @@ -5969,32 +6016,568 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T return err; } +gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice const &named_args, Array *named_operands, bool show_error) { + bool success = true; -gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContext *c, Operand *operand, Ast *call) { - Type *proc_type = nullptr; + type = base_type(type); + if (named_args.count > 0) { + TypeProc *pt = nullptr; + if (is_type_proc(type)) { + pt = &type->Proc; + } + + for_array(i, named_args) { + Ast *arg = named_args[i]; + if (arg->kind != Ast_FieldValue) { + if (show_error) { + error(arg, "Expected a 'field = value'"); + } + return false; + } + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + gb_string_free(expr_str); + } + success = false; + continue; + } + String key = fv->field->Ident.token.string; + Ast *value = fv->value; + + Type *type_hint = nullptr; + if (pt) { + isize param_index = lookup_procedure_parameter(pt, key); + if (param_index < 0) { + if (show_error) { + error(value, "No parameter named '%.*s' for this procedure type %s", LIT(key), type_to_string(type)); + } + success = false; + continue; + } + + // bool prev_visited = visited[param_index]; + // if (prev_visited) { + // error(value, "Duplicate parameter named '%.*s' in procedure call", LIT(key)); + // success = false; + // } + + Entity *e = pt->params->Tuple.variables[param_index]; + if (!is_type_polymorphic(e->type)) { + type_hint = e->type; + } + + } + Operand o = {}; + check_expr_with_type_hint(c, &o, value, type_hint); + if (o.mode == Addressing_Invalid) { + success = false; + } + array_add(named_operands, o); + } + + } + return success; +} + + +gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(CheckerContext *c, Operand *operand, Ast *call) { + ast_node(ce, CallExpr, call); + GB_ASSERT(ce->split_args != nullptr); + + Slice const &positional_args = ce->split_args->positional; + Slice const &named_args = ce->split_args->named; CallArgumentData data = {}; data.result_type = t_invalid; - proc_type = base_type(operand->type); + GB_ASSERT(operand->mode == Addressing_ProcGroup); + auto procs = proc_group_entities_cloned(c, *operand); + + if (procs.count > 1) { + isize max_arg_count = positional_args.count + named_args.count; + for (Ast *arg : positional_args) { + // NOTE(bill): The only thing that may have multiple values + // will be a call expression (assuming `or_return` and `()` will be stripped) + arg = strip_or_return_expr(arg); + if (arg && arg->kind == Ast_CallExpr) { + max_arg_count = ISIZE_MAX; + break; + } + } + if (max_arg_count != ISIZE_MAX) for (Ast *arg : named_args) { + // NOTE(bill): The only thing that may have multiple values + // will be a call expression (assuming `or_return` and `()` will be stripped) + if (arg->kind == Ast_FieldValue) { + arg = strip_or_return_expr(arg->FieldValue.value); + if (arg && arg->kind == Ast_CallExpr) { + max_arg_count = ISIZE_MAX; + break; + } + } + } - if (operand->mode == Addressing_ProcGroup) { - Array procs = proc_group_entities(c, *operand); - if (procs.count == 1) { - proc_type = base_type(procs[0]->type); - } else { - error(call, "Procedure groups >1 not yet supported"); + for (isize proc_index = 0; proc_index < procs.count; /**/) { + Entity *proc = procs[proc_index]; + Type *pt = base_type(proc->type); + if (!(pt != nullptr && is_type_proc(pt))) { + proc_index++; + continue; + } + + isize param_count = 0; + isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(pt, ¶m_count); + + if (param_count_excluding_defaults > max_arg_count) { + array_unordered_remove(&procs, proc_index); + continue; + } + + // for (Ast *arg : named_args) { + // if (arg->kind != Ast_FieldValue) { + // continue; + // } + // ast_node(fv, FieldValue, arg); + // if (fv->field->kind != Ast_Ident) { + // continue; + // } + // bool ok = false; + // String key = fv->field->Ident.token.string; + // if (param_count) for (Entity *e : pt->Proc.params->Tuple.variables) { + // if (e->token.string == key) { + // ok = true; + // break; + // } + // } + // if (!ok) { + // if (proc_index < procs.count) { + // array_unordered_remove(&procs, proc_index); + // continue; + // } else { + // break; + // } + // } + // } + + proc_index++; + } + } + + Entity **lhs = nullptr; + isize lhs_count = -1; + bool is_variadic = false; + + auto positional_operands = array_make(heap_allocator(), 0, 0); + auto named_operands = array_make(heap_allocator(), 0, 0); + defer (array_free(&positional_operands)); + defer (array_free(&named_operands)); + + if (procs.count == 1) { + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } + + + Entity *e = procs[0]; + + lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + + if (!check_named_arguments(c, e->type, named_args, &named_operands, true)) { + return data; + } + + CallArgumentError err = check_call_arguments_internal(c, call, e->type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); + if (err != CallArgumentError_None) { + // handle error + } + + Type *proc_type = base_type(operand->type); + + Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; + add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + + proc_type = base_type(entity_to_use->type); + } + + if (proc_type && proc_type->kind == Type_Proc) { + data.result_type = proc_type->Proc.results; + add_type_and_value(c, operand->expr, operand->mode, proc_type, operand->value); + } else if (err == CallArgumentError_None) { + data.result_type = nullptr; + } + + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + CheckerContext ctx = *c; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } + } + return data; + } + + { + // NOTE(bill, 2019-07-13): This code is used to improve the type inference for procedure groups + // where the same positional parameter has the same type value (and ellipsis) + bool proc_arg_count_all_equal = true; + isize proc_arg_count = -1; + for (Entity *p : procs) { + Type *pt = base_type(p->type); + if (pt != nullptr && is_type_proc(pt)) { + if (proc_arg_count < 0) { + proc_arg_count = pt->Proc.param_count; + } else { + if (proc_arg_count != pt->Proc.param_count) { + proc_arg_count_all_equal = false; + break; + } + } + } + } + + if (proc_arg_count >= 0 && proc_arg_count_all_equal) { + lhs_count = proc_arg_count; + if (lhs_count > 0) { + lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count); + for (isize param_index = 0; param_index < lhs_count; param_index++) { + Entity *e = nullptr; + for (Entity *p : procs) { + Type *pt = base_type(p->type); + if (!(pt != nullptr && is_type_proc(pt))) { + continue; + } + + if (e == nullptr) { + e = pt->Proc.params->Tuple.variables[param_index]; + } else { + Entity *f = pt->Proc.params->Tuple.variables[param_index]; + if (e == f) { + continue; + } + if (are_types_identical(e->type, f->type)) { + bool ee = (e->flags & EntityFlag_Ellipsis) != 0; + bool fe = (f->flags & EntityFlag_Ellipsis) != 0; + if (ee == fe) { + continue; + } + } + // NOTE(bill): Entities are not close enough to be used + e = nullptr; + break; + } + } + lhs[param_index] = e; + } + } + } + } + + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + + for_array(i, named_args) { + Ast *arg = named_args[i]; + if (arg->kind != Ast_FieldValue) { + error(arg, "Expected a 'field = value'"); + return data; + } + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + gb_string_free(expr_str); return data; } + String key = fv->field->Ident.token.string; + Ast *value = fv->value; + + Type *type_hint = nullptr; + + for (isize lhs_idx = 0; lhs_idx < lhs_count; lhs_idx++) { + Entity *e = lhs[lhs_idx]; + if (e != nullptr && e->token.string == key && + !is_type_polymorphic(e->type)) { + type_hint = e->type; + break; + } + } + Operand o = {}; + check_expr_with_type_hint(c, &o, value, type_hint); + array_add(&named_operands, o); } - if (proc_type == nullptr || proc_type->kind != Type_Proc) { - gbString s = type_to_string(proc_type); - error(call, "Expected a procedure to call, got %s", s); - gb_string_free(s); + gb_free(heap_allocator(), lhs); + + auto valids = array_make(heap_allocator(), 0, procs.count); + defer (array_free(&valids)); + + auto proc_entities = array_make(heap_allocator(), 0, procs.count*2 + 1); + defer (array_free(&proc_entities)); + for (Entity *proc : procs) { + array_add(&proc_entities, proc); + } + + + gbString expr_name = expr_to_string(operand->expr); + defer (gb_string_free(expr_name)); + + for_array(i, procs) { + Entity *p = procs[i]; + Type *pt = base_type(p->type); + if (pt != nullptr && is_type_proc(pt)) { + CallArgumentError err = CallArgumentError_None; + CallArgumentData data = {}; + CheckerContext ctx = *c; + + ctx.no_polymorphic_errors = true; + ctx.allow_polymorphic_types = is_type_polymorphic(pt); + ctx.hide_polymorphic_errors = true; + + err = check_call_arguments_internal(&ctx, call, pt, p, positional_operands, named_operands, CallArgumentMode_NoErrors, &data); + if (err != CallArgumentError_None) { + continue; + } + isize index = i; + + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + if (!evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) { + continue; + } + + array_add(&proc_entities, data.gen_entity); + index = proc_entities.count-1; + } + + ValidIndexAndScore item = {}; + item.index = index; + item.score = data.score; + array_add(&valids, item); + } + } + + if (valids.count > 1) { + gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp); + i64 best_score = valids[0].score; + Entity *best_entity = proc_entities[valids[0].index]; + GB_ASSERT(best_entity != nullptr); + for (isize i = 1; i < valids.count; i++) { + if (best_score > valids[i].score) { + valids.count = i; + break; + } + if (best_entity == proc_entities[valids[i].index]) { + valids.count = i; + break; + } + } + } + + auto print_argument_types = [&]() { + error_line("\tGiven argument types: ("); + isize i = 0; + for (Operand const &o : positional_operands) { + if (i++ > 0) error_line(", "); + gbString type = type_to_string(o.type); + defer (gb_string_free(type)); + error_line("%s", type); + } + for (Operand const &o : named_operands) { + if (i++ > 0) error_line(", "); + + gbString type = type_to_string(o.type); + defer (gb_string_free(type)); + + if (i < ce->split_args->named.count) { + Ast *named_field = ce->split_args->named[i]; + ast_node(fv, FieldValue, named_field); + + gbString field = expr_to_string(fv->field); + defer (gb_string_free(field)); + + error_line("%s = %s", field, type); + } else { + error_line("%s", type); + } + } + error_line(")\n"); + }; + + if (valids.count == 0) { + begin_error_block(); + defer (end_error_block()); + + error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name); + if (positional_operands.count == 0 && named_operands.count == 0) { + error_line("\tNo given arguments\n"); + } else { + print_argument_types(); + } + + if (procs.count > 0) { + error_line("Did you mean to use one of the following:\n"); + } + for (Entity *proc : procs) { + TokenPos pos = proc->token.pos; + Type *t = base_type(proc->type); + if (t == t_invalid) continue; + GB_ASSERT(t->kind == Type_Proc); + gbString pt; + defer (gb_string_free(pt)); + if (t->Proc.node != nullptr) { + pt = expr_to_string(t->Proc.node); + } else { + pt = type_to_string(t); + } + String prefix = {}; + String prefix_sep = {}; + if (proc->pkg) { + prefix = proc->pkg->name; + prefix_sep = str_lit("."); + } + String name = proc->token.string; + + char const *sep = "::"; + if (proc->kind == Entity_Variable) { + sep = ":="; + } + error_line("\t%.*s%.*s%.*s %s %s at %s\n", LIT(prefix), LIT(prefix_sep), LIT(name), sep, pt, token_pos_to_string(pos)); + } + if (procs.count > 0) { + error_line("\n"); + } + + data.result_type = t_invalid; + } else if (valids.count > 1) { + begin_error_block(); + defer (end_error_block()); + + error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name); + print_argument_types(); + + for (isize i = 0; i < valids.count; i++) { + Entity *proc = proc_entities[valids[i].index]; + GB_ASSERT(proc != nullptr); + TokenPos pos = proc->token.pos; + Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc); + gbString pt = nullptr; + defer (gb_string_free(pt)); + if (t->Proc.node != nullptr) { + pt = expr_to_string(t->Proc.node); + } else { + pt = type_to_string(t); + } + String name = proc->token.string; + char const *sep = "::"; + if (proc->kind == Entity_Variable) { + sep = ":="; + } + error_line("\t%.*s %s %s ", LIT(name), sep, pt); + if (proc->decl_info->proc_lit != nullptr) { + GB_ASSERT(proc->decl_info->proc_lit->kind == Ast_ProcLit); + auto *pl = &proc->decl_info->proc_lit->ProcLit; + if (pl->where_token.kind != Token_Invalid) { + error_line("\n\t\twhere "); + for_array(j, pl->where_clauses) { + Ast *clause = pl->where_clauses[j]; + if (j != 0) { + error_line("\t\t "); + } + gbString str = expr_to_string(clause); + error_line("%s", str); + gb_string_free(str); + + if (j != pl->where_clauses.count-1) { + error_line(","); + } + } + error_line("\n\t"); + } + } + error_line("at %s\n", token_pos_to_string(pos)); + } + data.result_type = t_invalid; + } else { + GB_ASSERT(valids.count == 1); + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } + + Entity *e = proc_entities[valids[0].index]; + GB_ASSERT(e != nullptr); + + Array named_operands = {}; + + Type *proc_type = e->type; + CallArgumentData data = {}; + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); + gb_unused(err); + Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; + add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + } + + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + CheckerContext ctx = *c; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } + } return data; } + return data; +} + + +gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContext *c, Operand *operand, Ast *call) { + Type *proc_type = nullptr; + + CallArgumentData data = {}; + data.result_type = t_invalid; + + proc_type = base_type(operand->type); + if (proc_type != nullptr && is_type_polymorphic(proc_type)) { error(call, "Polymorphic procedures not yet supported"); return data; @@ -6012,19 +6595,38 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex bool vari_expand = (ce->ellipsis.pos.line != 0); - auto positional_args = ce->args; - for (isize i = 0; i < ce->args.count; i++) { - Ast *arg = ce->args.data[i]; - if (arg->kind == Ast_FieldValue) { - positional_args.count = i; - break; + // Split positional and named args into separate arrays/slices + Slice positional_args = {}; + Slice named_args = {}; + + if (ce->split_args == nullptr) { + positional_args = ce->args; + for (isize i = 0; i < ce->args.count; i++) { + Ast *arg = ce->args.data[i]; + if (arg->kind == Ast_FieldValue) { + positional_args.count = i; + break; + } } + named_args = slice(ce->args, positional_args.count, ce->args.count); + + auto split_args = gb_alloc_item(permanent_allocator(), AstSplitArgs); + split_args->positional = positional_args; + split_args->named = named_args; + ce->split_args = split_args; + } else { + positional_args = ce->split_args->positional; + named_args = ce->split_args->named; + } + + if (operand->mode == Addressing_ProcGroup) { + return check_call_arguments_new_and_improved_proc_group(c, operand, call); } - auto named_args = slice(ce->args, positional_args.count, ce->args.count); + auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); - auto variadic_operands = array_make(heap_allocator(), 0, 0); - auto named_operands = array_make(heap_allocator(), 0, 0); + auto variadic_operands = array_make(heap_allocator(), 0, 0); + auto named_operands = array_make(heap_allocator(), 0, 0); defer (array_free(&positional_operands)); defer (array_free(&variadic_operands)); @@ -6038,14 +6640,16 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex isize lhs_count = -1; bool is_variadic = false; Entity **lhs = nullptr; - if (proc_type != nullptr && is_type_proc(proc_type)) { + if (pt != nullptr) { lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + } else if (operand->mode == Addressing_ProcGroup) { + // TODO } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } positional_operand_count = positional_operands.count; - if (proc_type != nullptr) { + if (pt != nullptr) { visited = slice_make(temporary_allocator(), pt->param_count); if (!pt->variadic) { @@ -6161,7 +6765,7 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex string_map_init(&type_hint_map, 2*named_args.count); defer (string_map_destroy(&type_hint_map)); - if (proc_type != nullptr) { + if (pt != nullptr) { TypeTuple *param_tuple = &pt->params->Tuple; for (Entity *e : param_tuple->variables) { if (is_blank_ident(e->token)) { @@ -6252,7 +6856,7 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex } - if (proc_type != nullptr) { + if (pt != nullptr) { if (pt->variadic) { visited[pt->variadic_index] = true; } @@ -6293,14 +6897,45 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex return data; } + { + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } - auto ordered_args = gb_alloc_item(permanent_allocator(), AstOrderedArgs); - ordered_args->positional = positional_args; - ordered_args->named = named_args; + Entity *e = entity_of_node(ident); - ce->ordered_args = ordered_args; + Array operands = array_clone(heap_allocator(), positional_operands); - if (proc_type != nullptr) { + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); + gb_unused(err); + Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; + add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + } + if (data.gen_entity != nullptr) { + Entity *e = data.gen_entity; + DeclInfo *decl = data.gen_entity->decl_info; + CheckerContext ctx = *c; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); + decl->where_clauses_evaluated = true; + + if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } + } + } + + if (pt != nullptr) { data.result_type = pt->results; } return data; @@ -6438,13 +7073,13 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op break; } } - if (all_non_poly && (procs.count == 1 || c->pkg->name == "bug")) { - return check_call_arguments_single_procedure(c, operand, call); + if (all_non_poly) { + return check_call_arguments_new_and_improved(c, operand, call); } } if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) { - return check_call_arguments_single_procedure(c, operand, call); + return check_call_arguments_new_and_improved(c, operand, call); } ast_node(ce, CallExpr, call); @@ -6635,8 +7270,9 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + Array named_operands = {}; CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data); + CallArgumentError err = call_checker(c, call, e->type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); if (err != CallArgumentError_None) { // handle error } @@ -6740,7 +7376,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op ctx.allow_polymorphic_types = is_type_polymorphic(pt); ctx.hide_polymorphic_errors = true; - err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data); + Array named_operands = {}; + err = call_checker(&ctx, call, pt, p, operands, named_operands, CallArgumentMode_NoErrors, &data); if (err != CallArgumentError_None) { continue; } @@ -6910,9 +7547,11 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op Entity *e = proc_entities[valids[0].index]; GB_ASSERT(e != nullptr); + Array named_operands = {}; + proc_type = e->type; CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); + CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; add_entity_use(c, ident, entity_to_use); @@ -6949,9 +7588,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op Entity *e = entity_of_node(ident); + Array named_operands = {}; CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); + CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; add_entity_use(c, ident, entity_to_use); diff --git a/src/error.cpp b/src/error.cpp index defc2593f..eb010eb36 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -265,7 +265,8 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { defer (gb_string_free(the_line)); if (the_line != nullptr) { - String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); + char const *line_text = the_line; + isize line_len = gb_string_length(the_line); // TODO(bill): This assumes ASCII @@ -285,21 +286,27 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { isize squiggle_extra = 0; - if (line.len > MAX_LINE_LENGTH_PADDED) { + if (line_len > MAX_LINE_LENGTH_PADDED) { i32 left = MAX_TAB_WIDTH; - line.text += offset-left; - line.len -= offset-left; - offset = left+MAX_TAB_WIDTH/2; - if (line.len > MAX_LINE_LENGTH_PADDED) { - line.len = MAX_LINE_LENGTH_PADDED; - if (error_length > line.len-left) { - error_length = cast(i32)line.len - left; + if (offset > 0) { + line_text += offset-left; + line_len -= offset-left; + offset = left+MAX_TAB_WIDTH/2; + } + if (line_len > MAX_LINE_LENGTH_PADDED) { + line_len = MAX_LINE_LENGTH_PADDED; + if (error_length > line_len-left) { + error_length = cast(i32)line_len - left; squiggle_extra = 1; } } - error_out("... %.*s ...", LIT(line)); + if (offset > 0) { + error_out("... %.*s ...", cast(i32)line_len, line_text); + } else { + error_out("%.*s ...", cast(i32)line_len, line_text); + } } else { - error_out("%.*s", LIT(line)); + error_out("%.*s", cast(i32)line_len, line_text); } error_out("\n\t"); @@ -312,7 +319,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("^"); if (end.file_id == pos.file_id) { if (end.line > pos.line) { - for (i32 i = offset; i < line.len; i++) { + for (i32 i = offset; i < line_len; i++) { error_out("~"); } } else if (end.line == pos.line && end.column > pos.column) { diff --git a/src/gb/gb.h b/src/gb/gb.h index bc4c1f27d..3d4bff9b4 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -3299,12 +3299,39 @@ void const *gb_memrchr(void const *data, u8 c, isize n) { -gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment) { return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_alloc (gbAllocator a, isize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void gb_free (gbAllocator a, void *ptr) { if (ptr != NULL) a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void gb_free_all (gbAllocator a) { a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_resize (gbAllocator a, void *ptr, isize old_size, isize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); } +gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment) { + if (size == 0) { + return NULL; + } + return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); +} +gb_inline void *gb_alloc(gbAllocator a, isize size) { + return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); +} +gb_inline void gb_free(gbAllocator a, void *ptr) { + if (ptr != NULL) { + a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); + } +} +gb_inline void gb_free_all(gbAllocator a) { + a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); +} +gb_inline void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size) { + return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); +} +gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { + if (new_size == 0) { + if (ptr != NULL) { + return a.proc(a.data, gbAllocation_Free, 0, 0, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); + } + return NULL; + } else if (ptr == NULL) { + return a.proc(a.data, gbAllocation_Alloc, new_size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); + } else if (old_size == new_size && ((uintptr)ptr % (uintptr)alignment) == 0) { + return ptr; + } + return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); +} gb_inline void *gb_alloc_copy (gbAllocator a, void const *src, isize size) { return gb_memcopy(gb_alloc(a, size), src, size); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3c1cfe47c..046016c75 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3156,20 +3156,20 @@ gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lb array_add(args, value); } } -gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstOrderedArgs *ordered_args) { +gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstSplitArgs *split_args) { ast_node(ce, CallExpr, call); auto args = array_make(permanent_allocator(), 0, pt->param_count); bool vari_expand = (ce->ellipsis.pos.line != 0); - for_array(i, ordered_args->positional) { + for_array(i, split_args->positional) { Entity *e = pt->params->Tuple.variables[i]; GB_ASSERT(e->kind == Entity_Variable); if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); - auto variadic = slice(ordered_args->positional, pt->variadic_index, ordered_args->positional.count); + auto variadic = slice(split_args->positional, pt->variadic_index, split_args->positional.count); if (variadic.count != 0) { // variadic call argument generation Type *slice_type = e->type; @@ -3211,14 +3211,14 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedur break; } else { - lbValue value = lb_build_expr(p, ordered_args->positional[i]); + lbValue value = lb_build_expr(p, split_args->positional[i]); lb_add_values_to_array(p, &args, value); } } array_resize(&args, pt->param_count); - for (Ast *arg : ordered_args->named) { + for (Ast *arg : split_args->named) { ast_node(fv, FieldValue, arg); GB_ASSERT(fv->field->kind == Ast_Ident); String name = fv->field->Ident.token.string; @@ -3331,8 +3331,8 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - if (ce->ordered_args) { - return lb_build_call_expr_internal_with_arg_ordered_args(p, value, pt, expr, ce->ordered_args); + if (ce->split_args) { + return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args); } if (is_call_expr_field_value(ce)) { diff --git a/src/parser.hpp b/src/parser.hpp index e0e78fa1d..900fddbab 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -367,7 +367,7 @@ gb_global char const *union_type_kind_strings[UnionType_COUNT] = { "#shared_nil", }; -struct AstOrderedArgs { +struct AstSplitArgs { Slice positional; Slice named; }; @@ -447,7 +447,7 @@ AST_KIND(_ExprBegin, "", bool) \ ProcInlining inlining; \ bool optional_ok_one; \ bool was_selector; \ - AstOrderedArgs *ordered_args; \ + AstSplitArgs *split_args; \ }) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(EnumFieldValue, "enum field value", struct { \ diff --git a/src/types.cpp b/src/types.cpp index 3cc077f84..f3b7f5bab 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3326,6 +3326,9 @@ gb_internal bool are_struct_fields_reordered(Type *type) { type = base_type(type); GB_ASSERT(type->kind == Type_Struct); type_set_offsets(type); + if (type->Struct.fields.count == 0) { + return false; + } GB_ASSERT(type->Struct.offsets != nullptr); i64 prev_offset = 0; @@ -3344,6 +3347,9 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo type = base_type(type); GB_ASSERT(type->kind == Type_Struct); type_set_offsets(type); + if (type->Struct.fields.count == 0) { + return {}; + } GB_ASSERT(type->Struct.offsets != nullptr); auto indices = slice_make(allocator, type->Struct.fields.count); -- cgit v1.2.3 From f26e3c65098e5c95ac7d446f2a6db5f136c509f2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Jun 2023 22:26:43 +0100 Subject: Improve proc group selection with named arguments --- src/check_expr.cpp | 67 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 29 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e0c6be1d1..eb3713d82 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5314,7 +5314,7 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize * } -gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { +gb_internal isize lookup_procedure_parameter(TypeProc *pt, String const ¶meter_name) { isize param_count = pt->param_count; for (isize i = 0; i < param_count; i++) { Entity *e = pt->params->Tuple.variables[i]; @@ -5329,6 +5329,13 @@ gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name return -1; } +gb_internal isize lookup_procedure_parameter(Type *type, String const ¶meter_name) { + type = base_type(type); + GB_ASSERT(type->kind == Type_Proc); + return lookup_procedure_parameter(&type->Proc, parameter_name); +} + + gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { CallArgumentError err = CallArgumentError_None; @@ -6052,7 +6059,7 @@ gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slicekind != Ast_FieldValue) { + continue; + } + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + continue; + } + String key = fv->field->Ident.token.string; + for (isize proc_index = procs.count-1; proc_index >= 0; proc_index--) { + Type *t = procs[proc_index]->type; + if (is_type_proc(t)) { + isize param_index = lookup_procedure_parameter(t, key); + if (param_index < 0) { + array_unordered_remove(&procs, proc_index); + } + } + } + } + + if (procs.count == 0) { + // if any of the named arguments are wrong, the `procs` will be empty + // just start from scratch + array_free(&procs); + procs = proc_group_entities_cloned(c, *operand); + } + + // filter by positional argument length for (isize proc_index = 0; proc_index < procs.count; /**/) { Entity *proc = procs[proc_index]; Type *pt = base_type(proc->type); @@ -6134,33 +6170,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch array_unordered_remove(&procs, proc_index); continue; } - - // for (Ast *arg : named_args) { - // if (arg->kind != Ast_FieldValue) { - // continue; - // } - // ast_node(fv, FieldValue, arg); - // if (fv->field->kind != Ast_Ident) { - // continue; - // } - // bool ok = false; - // String key = fv->field->Ident.token.string; - // if (param_count) for (Entity *e : pt->Proc.params->Tuple.variables) { - // if (e->token.string == key) { - // ok = true; - // break; - // } - // } - // if (!ok) { - // if (proc_index < procs.count) { - // array_unordered_remove(&procs, proc_index); - // continue; - // } else { - // break; - // } - // } - // } - proc_index++; } } -- cgit v1.2.3 From 15a0d9f9008362882aed152ba3fecd09f4ce7b28 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Jun 2023 23:46:06 +0100 Subject: Begin to handle split arguments correctly --- src/check_expr.cpp | 548 ++++++++++++++++++++++++++--------------------------- 1 file changed, 273 insertions(+), 275 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index eb3713d82..92b572352 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -66,7 +66,7 @@ gb_internal int valid_index_and_score_cmp(void const *a, void const *b) { -#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); @@ -5351,77 +5351,280 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { i64 score = 0; bool show_error = show_error_mode == CallArgumentMode_ShowErrors; - auto ordered_operands = array_make(temporary_allocator(), pt->param_count); - bool *visited = gb_alloc_array(temporary_allocator(), bool, pt->param_count); + Type *final_proc_type = proc_type; + Entity *gen_entity = nullptr; + + if (vari_expand && !variadic) { + if (show_error) { + error(ce->ellipsis, + "Cannot use '..' in call to a non-variadic procedure: '%.*s'", + LIT(ce->proc->Ident.token.string)); + } + err = CallArgumentError_NonVariadicExpand; + } else if (vari_expand && pt->c_vararg) { + if (show_error) { + error(ce->ellipsis, + "Cannot use '..' in call to a '#c_vararg' variadic procedure: '%.*s'", + LIT(ce->proc->Ident.token.string)); + } + err = CallArgumentError_NonVariadicExpand; + } if (ce->split_args) { - GB_ASSERT(ce->split_args->named.count == named_operands.count); - for_array(i, ce->split_args->named) { - Ast *arg = ce->split_args->named[i]; - Operand operand = named_operands[i]; + auto ordered_operands = array_make(temporary_allocator(), pt->param_count); + auto visited = slice_make(temporary_allocator(), pt->param_count); - ast_node(fv, FieldValue, arg); - if (fv->field->kind != Ast_Ident) { - if (show_error) { - gbString expr_str = expr_to_string(fv->field); - error(arg, "Invalid parameter name '%s' in procedure call", expr_str); - gb_string_free(expr_str); + isize positional_operand_count = positional_operands.count; + if (variadic) { + positional_operand_count = gb_min(positional_operands.count, pt->variadic_index); + } else if (positional_operand_count > pt->param_count) { + err = CallArgumentError_TooManyArguments; + char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td"; + if (show_error) { + gbString proc_str = expr_to_string(ce->proc); + defer (gb_string_free(proc_str)); + error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count); + } + return err; + } + positional_operand_count = gb_min(positional_operand_count, pt->param_count); + + for (isize i = 0; i < positional_operand_count; i++) { + ordered_operands[i] = positional_operands[i]; + visited[i] = true; + } + + auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count); + + if (named_operands.count != 0) { + GB_ASSERT(ce->split_args->named.count == named_operands.count); + for_array(i, ce->split_args->named) { + Ast *arg = ce->split_args->named[i]; + Operand operand = named_operands[i]; + + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + gb_string_free(expr_str); + } + err = CallArgumentError_InvalidFieldValue; + continue; } - err = CallArgumentError_InvalidFieldValue; - continue; + String name = fv->field->Ident.token.string; + isize param_index = lookup_procedure_parameter(pt, name); + if (param_index < 0) { + if (show_error) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); + } + err = CallArgumentError_ParameterNotFound; + continue; + } + if (visited[param_index]) { + if (show_error) { + error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); + } + err = CallArgumentError_DuplicateParameter; + continue; + } + Entity *e = pt->params->Tuple.variables[param_index]; + + check_assignment(c, &operand, e->type, str_lit("named argument")); + + visited[param_index] = true; + ordered_operands[param_index] = operand; + + err = CallArgumentError_DuplicateParameter; } - String name = fv->field->Ident.token.string; - isize param_index = lookup_procedure_parameter(pt, name); - if (param_index < 0) { + } + + if (variadic) { + if (visited[pt->variadic_index] && + positional_operand_count < positional_operands.count) { if (show_error) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); + String name = pt->params->Tuple.variables[pt->variadic_index]->token.string; + error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name)); } - err = CallArgumentError_ParameterNotFound; - continue; + err = CallArgumentError_DuplicateParameter; + } else { + visited[pt->variadic_index] = true; + } + + } + + + for (Operand const &o : ordered_operands) { + if (o.mode != Addressing_Invalid) { + check_no_copy_assignment(o, str_lit("procedure call expression")); } - if (visited[param_index]) { + } + + for (isize i = 0; i < pt->param_count; i++) { + if (!visited[i]) { + Entity *e = pt->params->Tuple.variables[i]; + if (is_blank_ident(e->token)) { + continue; + } + if (e->kind == Entity_Variable) { + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + score += assign_score_function(1); + continue; + } + } + if (show_error) { - error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); + if (e->kind == Entity_TypeName) { + error(call, "Type parameter '%.*s' is missing in procedure call", + LIT(e->token.string)); + } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { + // Ignore + } else { + gbString str = type_to_string(e->type); + error(call, "Parameter '%.*s' of type '%s' is missing in procedure call", + LIT(e->token.string), str); + gb_string_free(str); + } } - err = CallArgumentError_DuplicateParameter; - continue; + err = CallArgumentError_ParameterMissing; } + } - visited[param_index] = true; - ordered_operands[param_index] = operand; + if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) { + err = CallArgumentError_None; - err = CallArgumentError_DuplicateParameter; + if (variadic) { + GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0); + Type *t = pt->params->Tuple.variables[0]->type; + if (is_type_polymorphic(t)) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); + err = CallArgumentError_AmbiguousPolymorphicVariadic; + } + } + } else { + if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) { + PolyProcData poly_proc_data = {}; + if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, call, &poly_proc_data)) { + gen_entity = poly_proc_data.gen_entity; + Type *gept = base_type(gen_entity->type); + GB_ASSERT(is_type_proc(gept)); + proc_type = gept; + pt = &gept->Proc; + } else { + err = CallArgumentError_WrongTypes; + } + } + + for (isize i = 0; i < pt->param_count; i++) { + Entity *e = pt->params->Tuple.variables[i]; + Operand *o = &ordered_operands[i]; + bool param_is_variadic = pt->variadic && pt->variadic_index == i; + + if (o->mode == Addressing_Invalid) { + if (param_is_variadic) { + Type *slice = e->type; + GB_ASSERT(is_type_slice(slice)); + Type *elem = base_type(slice)->Slice.elem; + + if (variadic_operands.count == 0) { + if (is_type_polymorphic(elem)) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); + err = CallArgumentError_AmbiguousPolymorphicVariadic; + return err; + } + } else { + if (vari_expand) { + GB_ASSERT(variadic_operands.count == 1); + check_assignment(c, &variadic_operands[0], slice, str_lit("variadic expanded argument")); + } else { + for (Operand &vo : variadic_operands) { + check_assignment(c, &vo, elem, str_lit("variadic argument")); + } + } + } + } + continue; + } + + if (e->kind == Entity_TypeName) { + GB_ASSERT(pt->is_polymorphic); + if (o->mode != Addressing_Type) { + if (show_error) { + error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string)); + } + err = CallArgumentError_WrongTypes; + } + if (are_types_identical(e->type, o->type)) { + score += assign_score_function(1); + } else { + score += assign_score_function(MAXIMUM_TYPE_DISTANCE); + } + } else { + i64 s = 0; + if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { + bool ok = false; + if (ok) { + s = assign_score_function(MAXIMUM_TYPE_DISTANCE); + } else { + if (show_error) { + check_assignment(c, o, e->type, str_lit("procedure argument")); + } + err = CallArgumentError_WrongTypes; + } + + if (e->flags & EntityFlag_ConstInput) { + if (o->mode != Addressing_Constant) { + if (show_error) { + error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); + } + err = CallArgumentError_NoneConstantParameter; + } + } + } else if (show_error) { + check_assignment(c, o, e->type, str_lit("procedure argument")); + } + score += s; + } + + if (o->mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o->type); + add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + } + } } - if (err) { - return err; + + if (data) { + data->score = score; + data->result_type = final_proc_type->Proc.results; + data->gen_entity = gen_entity; + + + Ast *proc_lit = nullptr; + if (ce->proc->tav.value.kind == ExactValue_Procedure) { + Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure); + if (vp && vp->kind == Ast_ProcLit) { + proc_lit = vp; + } + } + if (proc_lit == nullptr) { + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + } } + + return err; } + if (err) { + return err; + } + auto operands = positional_operands; TypeTuple *param_tuple = nullptr; if (pt->params != nullptr) { param_tuple = &pt->params->Tuple; } - - Type *final_proc_type = proc_type; - Entity *gen_entity = nullptr; - - if (vari_expand && !variadic) { - if (show_error) { - error(ce->ellipsis, - "Cannot use '..' in call to a non-variadic procedure: '%.*s'", - LIT(ce->proc->Ident.token.string)); - } - err = CallArgumentError_NonVariadicExpand; - } else if (vari_expand && pt->c_vararg) { - if (show_error) { - error(ce->ellipsis, - "Cannot use '..' in call to a '#c_vararg' variadic procedure: '%.*s'", - LIT(ce->proc->Ident.token.string)); - } - err = CallArgumentError_NonVariadicExpand; - } else if (operands.count == 0 && param_count_excluding_defaults == 0) { + if (operands.count == 0 && param_count_excluding_defaults == 0) { err = CallArgumentError_None; if (variadic) { @@ -5641,6 +5844,7 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { } gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { + auto operands = positional_operands; ast_node(ce, CallExpr, call); GB_ASSERT(is_type_proc(proc_type)); proc_type = base_type(proc_type); @@ -6705,37 +6909,26 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex return data; } + // if (pt->variadic) { + // isize param_index = pt->variadic_index; - for_array(i, positional_operands) { - Operand &o = positional_operands[i]; - isize param_index = i; + // Entity *e = pt->params->Tuple.variables[param_index]; + // GB_ASSERT(e->kind == Entity_Variable); + // GB_ASSERT(e->flags & EntityFlag_Ellipsis); + // GB_ASSERT(is_type_slice(e->type)); - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); - - check_assignment(c, &o, e->type, str_lit("procedure call expression")); - } - - if (pt->variadic) { - isize param_index = pt->variadic_index; - - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); - GB_ASSERT(e->flags & EntityFlag_Ellipsis); - GB_ASSERT(is_type_slice(e->type)); - - if (vari_expand) { - if (variadic_operands.count != 0) { - GB_ASSERT(variadic_operands.count == 1); - check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); - } - } else { - Type *elem = e->type->Slice.elem; - for (Operand &o : variadic_operands) { - check_assignment(c, &o, elem, str_lit("procedure call expression")); - } - } - } + // if (vari_expand) { + // if (variadic_operands.count != 0) { + // GB_ASSERT(variadic_operands.count == 1); + // check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); + // } + // } else { + // Type *elem = e->type->Slice.elem; + // for (Operand &o : variadic_operands) { + // check_assignment(c, &o, elem, str_lit("procedure call expression")); + // } + // } + // } array_resize(&positional_operands, pt->param_count); @@ -6770,68 +6963,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex array_add(&named_parameters, NamedParameter{name, fv->value}); } - StringMap type_hint_map = {}; // Key: String - string_map_init(&type_hint_map, 2*named_args.count); - defer (string_map_destroy(&type_hint_map)); - - if (pt != nullptr) { - TypeTuple *param_tuple = &pt->params->Tuple; - for (Entity *e : param_tuple->variables) { - if (is_blank_ident(e->token)) { - continue; - } - string_map_set(&type_hint_map, e->token.string, e->type); - } - } else if (operand->mode == Addressing_ProcGroup) { - Array procs = proc_group_entities(c, *operand); - for (Entity *proc : procs) { - Type *proc_type = base_type(proc->type); - if (is_type_proc(proc_type)) { - TypeProc *pt = &proc_type->Proc; - TypeTuple *param_tuple = nullptr; - if (pt->params != nullptr) { - param_tuple = &pt->params->Tuple; - } - if (param_tuple == nullptr) { - continue; - } - for (Entity *e : param_tuple->variables) { - if (is_blank_ident(e->token)) { - continue; - } - StringHashKey key = string_hash_string(e->token.string); - Type **found = string_map_get(&type_hint_map, key); - if (found) { - Type *t = *found; - if (t == nullptr) { - // NOTE(bill): Ambiguous named parameter across all types - continue; - } - if (are_types_identical(t, e->type)) { - // NOTE(bill): No need to set again - } else { - // NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr - string_map_set(&type_hint_map, key, cast(Type *)nullptr); - } - } else { - string_map_set(&type_hint_map, key, e->type); - } - } - } - } - } - - for (NamedParameter ¶m : named_parameters) { - Type *type_hint = nullptr; - if (Type **found = string_map_get(&type_hint_map, param.key)) { - type_hint = *found; - } - - Operand operand = {}; - check_expr_or_type(c, &operand, param.value, type_hint); - array_add(&named_operands, operand); - } - for (NamedParameter const ¶m : named_parameters) { isize param_index = lookup_procedure_parameter(pt, param.key); if (param_index < 0) { @@ -6856,11 +6987,10 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex any_failure = true; } - check_assignment(c, &o, e->type, str_lit("procedure call expression")); - if (!prev_visited) { positional_operands[param_index] = o; } + array_add(&named_operands, o); } } @@ -6891,17 +7021,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } } - for (Operand const &o : positional_operands) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - for (Operand const &o : variadic_operands) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - for (Operand const &o : named_operands) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - - if (any_failure) { return data; } @@ -6917,7 +7036,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Array operands = array_clone(heap_allocator(), positional_operands); - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, {}, CallArgumentMode_ShowErrors, &data); gb_unused(err); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; add_entity_use(c, ident, entity_to_use); @@ -6948,127 +7067,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex data.result_type = pt->results; } return data; -#if 0 - - - - /* - auto visited = slice_make(temporary_allocator(), pt->param_count); - auto ordered_values = slice_make(temporary_allocator(), pt->param_count); - - - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - - isize param_index = i; - String param_name = {}; - - if (arg->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, arg); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(arg, "Invalid parameter name '%s' in procedure call", expr_str); - any_failure = true; - gb_string_free(expr_str); - continue; - } - param_name = fv->field->Ident.token.string; - param_index = lookup_procedure_parameter(pt, param_name); - if (param_index < 0) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(param_name)); - any_failure = true; - continue; - } - arg = fv->value; - } else { - if (param_index >= pt->param_count) { - error(arg, "Too many parameters in procedure call, expected a maximum of %td, got %td", pt->param_count, ce->args.count); - any_failure = true; - break; - } - - param_name = pt->params->Tuple.variables[param_index]->token.string; - } - if (visited[param_index]) { - error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(param_name)); - any_failure = true; - } else { - ParameterValue value = {}; - value.kind = ParameterValue_Value; - value.original_ast_expr = arg; - value.ast_value = arg; - ordered_values[param_index] = value; - } - visited[param_index] = true; - } - - for (isize i = 0; i < pt->param_count; i++) { - if (!visited[i]) { - Entity *e = pt->params->Tuple.variables[i]; - if (e->kind == Entity_Variable && - has_parameter_value(e->Variable.param_value)) { - ordered_values[i] = e->Variable.param_value; - visited[i] = true; - } - } - } - - for (isize i = 0; i < visited.count; i++) { - if (!visited[i]) { - Entity *e = pt->params->Tuple.variables[i]; - gbString t = type_to_string(e->type); - defer (gb_string_free(t)); - if (is_blank_ident(e->token)) { - error(call, "Missing parameter of type '%s' at index %td", t, i); - } else { - error(call, "Missing parameter '%.*s' of type '%s'", LIT(e->token.string), t, i); - } - return data; - } - } - */ - if (any_failure) { - return data; - } - - Array operands = {}; - defer (array_free(&operands)); - - Ast *ident = unparen_expr(operand->expr); - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = unparen_expr(s); - } - - Entity *e = entity_of_node(ident); - - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); - gb_unused(err); - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - } - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - } - return data; -#endif } -- cgit v1.2.3 From 9ec927b9e952cb1e82ec543c95547321273a812b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 00:30:29 +0100 Subject: Try to get make everything work with parapoly --- src/check_expr.cpp | 186 ++++++++-------------------------------------- src/llvm_backend_proc.cpp | 7 +- src/types.cpp | 16 ++-- 3 files changed, 48 insertions(+), 161 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 92b572352..8242d38e9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6791,11 +6791,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex proc_type = base_type(operand->type); - if (proc_type != nullptr && is_type_polymorphic(proc_type)) { - error(call, "Polymorphic procedures not yet supported"); - return data; - } - TypeProc *pt = nullptr; if (proc_type) { pt = &proc_type->Proc; @@ -6806,7 +6801,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex bool any_failure = false; - bool vari_expand = (ce->ellipsis.pos.line != 0); + // bool vari_expand = (ce->ellipsis.pos.line != 0); // Split positional and named args into separate arrays/slices Slice positional_args = {}; @@ -6838,14 +6833,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); - auto variadic_operands = array_make(heap_allocator(), 0, 0); auto named_operands = array_make(heap_allocator(), 0, 0); defer (array_free(&positional_operands)); - defer (array_free(&variadic_operands)); defer (array_free(&named_operands)); - isize positional_operand_count = 0; Slice visited = {}; @@ -6860,90 +6852,8 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } - positional_operand_count = positional_operands.count; - - if (pt != nullptr) { - visited = slice_make(temporary_allocator(), pt->param_count); - - if (!pt->variadic) { - if (pt->param_count < positional_operands.count) { - char const *err_fmt = "Too many arguments for '%s', expected a maximum of %td arguments, got %td"; - gbString c = expr_to_string(ce->proc); - error(call, err_fmt, c, pt->param_count, positional_operands.count); - gb_string_free(c); - return data; - } - positional_operand_count = positional_operands.count; - } else { - // only state it is visited if it was set later on - visited[pt->variadic_index] = positional_operand_count > pt->variadic_index; - - positional_operand_count = gb_min(pt->variadic_index, positional_operand_count); - } - - - for (isize i = 0; i < positional_operand_count; i++) { - visited[i] = true; - } - - for (isize i = positional_operand_count; i < positional_operands.count; i++) { - array_add(&variadic_operands, positional_operands[i]); - } - array_resize(&positional_operands, positional_operand_count); - - if (vari_expand) { - if (variadic_operands.count > 1) { - error(variadic_operands[1].expr, "Unexpected position arguments after variadic expansion with '..'"); - return data; - } - } - - isize param_count = 0; - isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); - - if (named_args.count == 0 && positional_operands.count < param_count_excluding_defaults) { - char const *err_fmt = "Too few arguments for '%s', expected a minimum of %td arguments, got %td"; - gbString c = expr_to_string(ce->proc); - error(call, err_fmt, c, param_count_excluding_defaults, positional_operands.count); - gb_string_free(c); - return data; - } - - // if (pt->variadic) { - // isize param_index = pt->variadic_index; - - // Entity *e = pt->params->Tuple.variables[param_index]; - // GB_ASSERT(e->kind == Entity_Variable); - // GB_ASSERT(e->flags & EntityFlag_Ellipsis); - // GB_ASSERT(is_type_slice(e->type)); - - // if (vari_expand) { - // if (variadic_operands.count != 0) { - // GB_ASSERT(variadic_operands.count == 1); - // check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression")); - // } - // } else { - // Type *elem = e->type->Slice.elem; - // for (Operand &o : variadic_operands) { - // check_assignment(c, &o, elem, str_lit("procedure call expression")); - // } - // } - // } - - array_resize(&positional_operands, pt->param_count); - - } - if (named_args.count > 0) { - struct NamedParameter { - String key; - Ast * value; - }; - - auto named_parameters = array_make(heap_allocator(), 0, named_args.count); - defer (array_free(&named_parameters)); - for_array(i, named_args) { Ast *arg = named_args[i]; if (arg->kind != Ast_FieldValue) { @@ -6958,74 +6868,27 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex gb_string_free(expr_str); continue; } - String name = fv->field->Ident.token.string; - - array_add(&named_parameters, NamedParameter{name, fv->value}); - } - - for (NamedParameter const ¶m : named_parameters) { - isize param_index = lookup_procedure_parameter(pt, param.key); - if (param_index < 0) { - error(param.value, "No parameter named '%.*s' for this procedure type", LIT(param.key)); - any_failure = true; - continue; - } - - bool prev_visited = visited[param_index]; - visited[param_index] = true; + String key = fv->field->Ident.token.string; + Ast *value = fv->value; - if (prev_visited) { - error(param.value, "Duplicate parameter named '%.*s' in procedure call", LIT(param.key)); + isize param_index = lookup_procedure_parameter(pt, key); + Type *type_hint = nullptr; + if (param_index >= 0) { + Entity *e = pt->params->Tuple.variables[param_index]; + type_hint = e->type; } - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); - Operand o = {}; - check_expr_with_type_hint(c, &o, param.value, e->type); + check_expr_with_type_hint(c, &o, value, type_hint); if (o.mode == Addressing_Invalid) { any_failure = true; } - - if (!prev_visited) { - positional_operands[param_index] = o; - } array_add(&named_operands, o); } } - if (pt != nullptr) { - if (pt->variadic) { - visited[pt->variadic_index] = true; - } - - for_array(i, visited) { - if (!visited[i]) { - if (pt->variadic && i == pt->variadic_index) { - visited[i] = true; - continue; - } - - Entity *e = pt->params->Tuple.variables[i]; - if (e->kind == Entity_Variable) { - if (has_parameter_value(e->Variable.param_value)) { - visited[i] = true; - continue; - } - } - gbString t = type_to_string(e->type); - error(call, "Missing parameter of type '%s' at index %td", t, i); - gb_string_free(t); - } - } - } - - if (any_failure) { - return data; - } - - { + if (!any_failure) { Ast *ident = operand->expr; while (ident->kind == Ast_SelectorExpr) { Ast *s = ident->SelectorExpr.selector; @@ -7034,9 +6897,12 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Entity *e = entity_of_node(ident); - Array operands = array_clone(heap_allocator(), positional_operands); + TokenPos pos = ast_token(call).pos; + if (pos.line == 282 && pos.column == 9 && is_type_polymorphic(proc_type)) { + // GB_PANIC("HERE! %s\n", expr_to_string(call)); + } - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, {}, CallArgumentMode_ShowErrors, &data); + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; add_entity_use(c, ident, entity_to_use); @@ -7060,12 +6926,17 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } - } - } - if (pt != nullptr) { + if (is_type_proc(data.gen_entity->type)) { + Type *t = base_type(entity_to_use->type); + // GB_ASSERT_MSG(!is_type_polymorphic(t), "%s", expr_to_string(call)); + data.result_type = t->Proc.results; + } + } + } else if (pt) { data.result_type = pt->results; } + return data; } @@ -7085,8 +6956,15 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } } - if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) { - return check_call_arguments_new_and_improved(c, operand, call); + if (operand->mode != Addressing_ProcGroup) { + bool is_poly = is_type_polymorphic(operand->type); + bool ok = !is_poly; + if (!ok && c->pkg->name == "bug") { + ok = true; + } + if (ok) { + return check_call_arguments_new_and_improved(c, operand, call); + } } ast_node(ce, CallExpr, call); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 046016c75..c6a9438ea 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3165,7 +3165,12 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure for_array(i, split_args->positional) { Entity *e = pt->params->Tuple.variables[i]; - GB_ASSERT(e->kind == Entity_Variable); + if (e->kind == Entity_TypeName) { + array_add(&args, lb_const_nil(p->module, e->type)); + continue; + } else if (e->kind != Entity_Variable) { + continue; + } if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); diff --git a/src/types.cpp b/src/types.cpp index f3b7f5bab..1223132e3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2108,8 +2108,12 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { return is_type_polymorphic(t->Matrix.elem, or_specialized); case Type_Tuple: - for_array(i, t->Tuple.variables) { - if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) { + for (Entity *e : t->Tuple.variables) { + if (e->kind == Entity_Constant) { + if (e->Constant.value.kind != ExactValue_Invalid) { + return or_specialized; + } + } else if (is_type_polymorphic(e->type, or_specialized)) { return true; } } @@ -4279,6 +4283,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha if (var == nullptr) { continue; } + if (comma_index++ > 0) { + str = gb_string_appendc(str, ", "); + } + String name = var->token.string; if (var->kind == Entity_Constant) { str = gb_string_appendc(str, "$"); @@ -4295,10 +4303,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha continue; } - if (comma_index++ > 0) { - str = gb_string_appendc(str, ", "); - } - if (var->kind == Entity_Variable) { if (var->flags&EntityFlag_CVarArg) { str = gb_string_appendc(str, "#c_vararg "); -- cgit v1.2.3 From 7c57dde2556b95a0ef206efd93fc23f8fd0bdf89 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 13:47:10 +0100 Subject: Start work on parapoly args for new and improved --- src/check_expr.cpp | 18 ++++-------------- src/llvm_backend_proc.cpp | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8242d38e9..5574827d5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6898,9 +6898,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Entity *e = entity_of_node(ident); TokenPos pos = ast_token(call).pos; - if (pos.line == 282 && pos.column == 9 && is_type_polymorphic(proc_type)) { - // GB_PANIC("HERE! %s\n", expr_to_string(call)); - } CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); @@ -6908,6 +6905,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex add_entity_use(c, ident, entity_to_use); if (entity_to_use != nullptr) { update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; @@ -6931,6 +6929,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Type *t = base_type(entity_to_use->type); // GB_ASSERT_MSG(!is_type_polymorphic(t), "%s", expr_to_string(call)); data.result_type = t->Proc.results; + } } } else if (pt) { @@ -6954,17 +6953,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (all_non_poly) { return check_call_arguments_new_and_improved(c, operand, call); } - } - - if (operand->mode != Addressing_ProcGroup) { - bool is_poly = is_type_polymorphic(operand->type); - bool ok = !is_poly; - if (!ok && c->pkg->name == "bug") { - ok = true; - } - if (ok) { - return check_call_arguments_new_and_improved(c, operand, call); - } + } else { + return check_call_arguments_new_and_improved(c, operand, call); } ast_node(ce, CallExpr, call); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index c6a9438ea..b7ee88804 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3250,7 +3250,7 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); break; case Entity_Constant: - GB_PANIC("TODO constant parameter"); + args[i] = lb_handle_param_value(p, e->type, e->Constant.param_value, pos); break; } } else { -- cgit v1.2.3 From 26e06ba6a68bf9812b92d59629aaa426f2659a5f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 16:08:26 +0100 Subject: Correct `check_call_arguments_new_and_improved` logic --- src/check_expr.cpp | 139 +++++++++++++++++++++++++++++++++++++++++------------ src/check_stmt.cpp | 8 ++- src/check_type.cpp | 131 +++++++++++++++++++++++++------------------------- src/types.cpp | 2 - 4 files changed, 180 insertions(+), 100 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5574827d5..ac3886268 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -34,6 +34,7 @@ gb_global char const *CallArgumentError_strings[CallArgumentError_MAX] = { "ParameterMissing", "DuplicateParameter", "NoneConstantParameter", + "OutOfOrderParameters", }; @@ -95,7 +96,7 @@ gb_internal void check_stmt (CheckerContext *c, Ast *nod gb_internal void check_stmt_list (CheckerContext *c, Slice const &stmts, u32 flags); gb_internal void check_init_constant (CheckerContext *c, Entity *e, Operand *operand); gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value); -gb_internal bool check_procedure_type (CheckerContext *c, Type *type, Ast *proc_type_node, Array *operands = nullptr); +gb_internal bool check_procedure_type (CheckerContext *c, Type *type, Ast *proc_type_node, Array const *operands = nullptr); gb_internal void check_struct_type (CheckerContext *c, Type *struct_type, Ast *node, Array *poly_operands, Type *named_type = nullptr, Type *original_type_for_poly = nullptr); gb_internal void check_union_type (CheckerContext *c, Type *union_type, Ast *node, Array *poly_operands, @@ -338,7 +339,7 @@ gb_internal void check_scope_decls(CheckerContext *c, Slice const &nodes, } gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, Entity *base_entity, Type *type, - Array *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { + Array const *param_operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { /////////////////////////////////////////////////////////////////////////////// // // // TODO CLEANUP(bill): This procedure is very messy and hacky. Clean this!!! // @@ -605,7 +606,7 @@ gb_internal bool check_polymorphic_procedure_assignment(CheckerContext *c, Opera return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_def_node, poly_proc_data); } -gb_internal bool find_or_generate_polymorphic_procedure_from_parameters(CheckerContext *c, Entity *base_entity, Array *operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { +gb_internal bool find_or_generate_polymorphic_procedure_from_parameters(CheckerContext *c, Entity *base_entity, Array const *operands, Ast *poly_def_node, PolyProcData *poly_proc_data) { return find_or_generate_polymorphic_procedure(c, base_entity, nullptr, operands, poly_def_node, poly_proc_data); } @@ -5337,6 +5338,8 @@ gb_internal isize lookup_procedure_parameter(Type *type, String const ¶meter gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { + TEMPORARY_ALLOCATOR_GUARD(); + CallArgumentError err = CallArgumentError_None; ast_node(ce, CallExpr, call); @@ -5371,8 +5374,19 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } if (ce->split_args) { - auto ordered_operands = array_make(temporary_allocator(), pt->param_count); auto visited = slice_make(temporary_allocator(), pt->param_count); + auto ordered_operands = array_make(temporary_allocator(), pt->param_count); + defer ({ + for (Operand const &o : ordered_operands) { + if (o.expr != nullptr) { + call->viral_state_flags |= o.expr->viral_state_flags; + } + } + }); + + if (check_order_of_call_arguments(c, proc_type, call, show_error)) { + return CallArgumentError_OutOfOrderParameters; + } isize positional_operand_count = positional_operands.count; if (variadic) { @@ -5449,11 +5463,36 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { err = CallArgumentError_DuplicateParameter; } else { visited[pt->variadic_index] = true; + + if (vari_expand) { + GB_ASSERT(variadic_operands.count != 0); + ordered_operands[pt->variadic_index] = variadic_operands[0]; + } else { + AstFile *f = call->file(); + + // HACK(bill): this is an awful hack + Operand o = {}; + o.mode = Addressing_Value; + o.expr = ast_ident(f, make_token_ident("nil")); + o.expr->Ident.token.pos = ast_token(call).pos; + if (variadic_operands.count != 0) { + o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos; + + Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; + if (is_type_polymorphic(vt->type)) { + o.type = alloc_type_slice(default_type(variadic_operands[0].type)); + } else { + o.type = vt->type; + } + } else { + o.type = t_untyped_nil; + } + ordered_operands[pt->variadic_index] = o; + } } } - for (Operand const &o : ordered_operands) { if (o.mode != Addressing_Invalid) { check_no_copy_assignment(o, str_lit("procedure call expression")); @@ -5508,44 +5547,23 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { gen_entity = poly_proc_data.gen_entity; Type *gept = base_type(gen_entity->type); GB_ASSERT(is_type_proc(gept)); - proc_type = gept; + final_proc_type = gen_entity->type; pt = &gept->Proc; + } else { err = CallArgumentError_WrongTypes; } } for (isize i = 0; i < pt->param_count; i++) { - Entity *e = pt->params->Tuple.variables[i]; Operand *o = &ordered_operands[i]; - bool param_is_variadic = pt->variadic && pt->variadic_index == i; - if (o->mode == Addressing_Invalid) { - if (param_is_variadic) { - Type *slice = e->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - - if (variadic_operands.count == 0) { - if (is_type_polymorphic(elem)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); - err = CallArgumentError_AmbiguousPolymorphicVariadic; - return err; - } - } else { - if (vari_expand) { - GB_ASSERT(variadic_operands.count == 1); - check_assignment(c, &variadic_operands[0], slice, str_lit("variadic expanded argument")); - } else { - for (Operand &vo : variadic_operands) { - check_assignment(c, &vo, elem, str_lit("variadic argument")); - } - } - } - } continue; } + Entity *e = pt->params->Tuple.variables[i]; + bool param_is_variadic = pt->variadic && pt->variadic_index == i; + if (e->kind == Entity_TypeName) { GB_ASSERT(pt->is_polymorphic); if (o->mode != Addressing_Type) { @@ -5563,6 +5581,11 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { i64 s = 0; if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { bool ok = false; + if (e->flags & EntityFlag_AnyInt) { + if (is_type_integer(e->type)) { + ok = check_is_castable_to(c, o, e->type); + } + } if (ok) { s = assign_score_function(MAXIMUM_TYPE_DISTANCE); } else { @@ -5589,6 +5612,57 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (o->mode == Addressing_Type && is_type_typeid(e->type)) { add_type_info_type(c, o->type); add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + } else if (show_error && is_type_untyped(o->type)) { + update_untyped_expr_type(c, o->expr, e->type, true); + } + } + } + + if (variadic) { + Type *slice = pt->params->Tuple.variables[pt->variadic_index]->type; + GB_ASSERT(is_type_slice(slice)); + Type *elem = base_type(slice)->Slice.elem; + Type *t = elem; + + if (is_type_polymorphic(t)) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + err = CallArgumentError_AmbiguousPolymorphicVariadic; + } + + for_array(operand_index, variadic_operands) { + Operand &o = variadic_operands[operand_index]; + if (vari_expand) { + t = slice; + if (operand_index > 0) { + if (show_error) { + error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end"); + } + if (data) { + data->score = score; + data->result_type = final_proc_type->Proc.results; + data->gen_entity = gen_entity; + } + return CallArgumentError_MultipleVariadicExpand; + } + } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("variadic argument")); + } + err = CallArgumentError_WrongTypes; + } else if (show_error) { + check_assignment(c, &o, t, str_lit("variadic argument")); + } + score += s; + if (is_type_any(elem)) { + add_type_info_type(c, o.type); + } + if (o.mode == Addressing_Type && is_type_typeid(t)) { + add_type_info_type(c, o.type); + add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); + } else if (show_error && is_type_untyped(o.type)) { + update_untyped_expr_type(c, o.expr, t, true); } } } @@ -6756,6 +6830,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch add_entity_use(c, ident, entity_to_use); if (entity_to_use != nullptr) { update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } if (data.gen_entity != nullptr) { @@ -6950,7 +7025,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op break; } } - if (all_non_poly) { + if (true) { return check_call_arguments_new_and_improved(c, operand, call); } } else { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 09af496ab..cf6f998e5 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2207,7 +2207,13 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { } else if (operands.count != result_count) { // Ignore error message as it has most likely already been reported if (all_operands_valid(operands)) { - error(node, "Expected %td return values, got %td", result_count, operands.count); + if (operands.count == 1) { + gbString t = type_to_string(operands[0].type); + error(node, "Expected %td return values, got %td (%s)", result_count, operands.count, t); + gb_string_free(t); + } else { + error(node, "Expected %td return values, got %td", result_count, operands.count); + } } } else { for (isize i = 0; i < result_count; i++) { diff --git a/src/check_type.cpp b/src/check_type.cpp index a69dcdadc..f241f35ee 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1416,7 +1416,7 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_ } -gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array *operands) { +gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array const *operands) { if (_params == nullptr) { return nullptr; } @@ -1664,81 +1664,82 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para ExactValue poly_const = {}; if (operands != nullptr && variables.count < operands->count) { - Operand op = (*operands)[variables.count]; - if (op.expr == nullptr) { - // NOTE(bill): 2019-03-30 - // This is just to add the error message to determine_type_from_polymorphic which - // depends on valid position information - op.expr = _params; - op.mode = Addressing_Invalid; - op.type = t_invalid; - } - if (is_type_polymorphic_type) { - type = determine_type_from_polymorphic(ctx, type, op); - if (type == t_invalid) { - success = false; - } 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; - Entity *proc_entity = entity_from_expr(op.expr); - if ((proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure)) { - if (is_type_polymorphic(proc_entity->type, false)) { - error(op.expr, "Cannot determine complete type of partial polymorphic procedure"); + { + if (op.expr == nullptr) { + // NOTE(bill): 2019-03-30 + // This is just to add the error message to determine_type_from_polymorphic which + // depends on valid position information + op.expr = _params; + op.mode = Addressing_Invalid; + op.type = t_invalid; + } + if (is_type_polymorphic_type) { + type = determine_type_from_polymorphic(ctx, type, op); + if (type == t_invalid) { + success = false; + } 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; + Entity *proc_entity = entity_from_expr(op.expr); + if ((proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure)) { + if (is_type_polymorphic(proc_entity->type, false)) { + error(op.expr, "Cannot determine complete type of partial polymorphic procedure"); + } } } } - } - if (is_poly_name) { - bool valid = false; - if (is_type_proc(op.type)) { - Ast *expr = unparen_expr(op.expr); - Entity *proc_entity = entity_from_expr(expr); - if (proc_entity) { - poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr); - valid = true; - } else if (expr->kind == Ast_ProcLit) { - poly_const = exact_value_procedure(expr); - valid = true; + if (is_poly_name) { + bool valid = false; + if (is_type_proc(op.type)) { + Ast *expr = unparen_expr(op.expr); + Entity *proc_entity = entity_from_expr(expr); + if (proc_entity) { + poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr); + valid = true; + } else if (expr->kind == Ast_ProcLit) { + poly_const = exact_value_procedure(expr); + valid = true; + } } - } - if (!valid) { - if (op.mode == Addressing_Constant) { - poly_const = op.value; - } else { - error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); - success = false; + if (!valid) { + if (op.mode == Addressing_Constant) { + poly_const = op.value; + } else { + error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); + success = false; + } } } - } - if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) { - bool ok = true; - if (p->flags&FieldFlag_any_int) { - if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { - ok = false; - } else if (!check_is_castable_to(ctx, &op, type)) { - ok = false; + if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) { + bool ok = true; + if (p->flags&FieldFlag_any_int) { + if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { + ok = false; + } else if (!check_is_castable_to(ctx, &op, type)) { + ok = false; + } + } + if (!ok) { + success = false; + #if 0 + gbString got = type_to_string(op.type); + gbString expected = type_to_string(type); + error(op.expr, "Cannot assigned type to parameter, got type '%s', expected '%s'", got, expected); + gb_string_free(expected); + gb_string_free(got); + #endif } } - if (!ok) { + + if (is_type_untyped(default_type(type))) { + gbString str = type_to_string(type); + error(op.expr, "Cannot determine type from the parameter, got '%s'", str); + gb_string_free(str); success = false; - #if 0 - gbString got = type_to_string(op.type); - gbString expected = type_to_string(type); - error(op.expr, "Cannot assigned type to parameter, got type '%s', expected '%s'", got, expected); - gb_string_free(expected); - gb_string_free(got); - #endif + type = t_invalid; } } - - if (is_type_untyped(default_type(type))) { - gbString str = type_to_string(type); - error(op.expr, "Cannot determine type from the parameter, got '%s'", str); - gb_string_free(str); - success = false; - type = t_invalid; - } } if (p->flags&FieldFlag_no_alias) { @@ -1967,7 +1968,7 @@ gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_res // NOTE(bill): 'operands' is for generating non generic procedure type -gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array *operands) { +gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array const *operands) { ast_node(pt, ProcType, proc_type_node); if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) { diff --git a/src/types.cpp b/src/types.cpp index 1223132e3..385ca926d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2123,7 +2123,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { if (t->Proc.is_polymorphic) { return true; } - #if 1 if (t->Proc.param_count > 0 && is_type_polymorphic(t->Proc.params, or_specialized)) { return true; @@ -2132,7 +2131,6 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { is_type_polymorphic(t->Proc.results, or_specialized)) { return true; } - #endif break; case Type_Enum: -- cgit v1.2.3 From 3c5661b51b9da1d3017bf9d0082418627d832884 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 20:29:40 +0100 Subject: Allow for positional and named arguments in procedure calls --- src/check_expr.cpp | 1402 ++++++++-------------------------------------------- 1 file changed, 215 insertions(+), 1187 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ac3886268..05fd51119 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -67,11 +67,6 @@ gb_internal int valid_index_and_score_cmp(void const *a, void const *b) { -#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) -typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); - - - gb_internal void check_expr (CheckerContext *c, Operand *operand, Ast *expression); gb_internal void check_multi_expr (CheckerContext *c, Operand *operand, Ast *expression); gb_internal void check_multi_expr_or_type (CheckerContext *c, Operand *operand, Ast *expression); @@ -5336,8 +5331,7 @@ gb_internal isize lookup_procedure_parameter(Type *type, String const ¶meter return lookup_procedure_parameter(&type->Proc, parameter_name); } - -gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { +gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) { TEMPORARY_ALLOCATOR_GUARD(); CallArgumentError err = CallArgumentError_None; @@ -5373,517 +5367,300 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { err = CallArgumentError_NonVariadicExpand; } - if (ce->split_args) { - auto visited = slice_make(temporary_allocator(), pt->param_count); - auto ordered_operands = array_make(temporary_allocator(), pt->param_count); - defer ({ - for (Operand const &o : ordered_operands) { - if (o.expr != nullptr) { - call->viral_state_flags |= o.expr->viral_state_flags; - } + GB_ASSERT(ce->split_args); + auto visited = slice_make(temporary_allocator(), pt->param_count); + auto ordered_operands = array_make(temporary_allocator(), pt->param_count); + defer ({ + for (Operand const &o : ordered_operands) { + if (o.expr != nullptr) { + call->viral_state_flags |= o.expr->viral_state_flags; } - }); - - if (check_order_of_call_arguments(c, proc_type, call, show_error)) { - return CallArgumentError_OutOfOrderParameters; } + }); - isize positional_operand_count = positional_operands.count; - if (variadic) { - positional_operand_count = gb_min(positional_operands.count, pt->variadic_index); - } else if (positional_operand_count > pt->param_count) { - err = CallArgumentError_TooManyArguments; - char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td"; - if (show_error) { - gbString proc_str = expr_to_string(ce->proc); - defer (gb_string_free(proc_str)); - error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count); - } - return err; - } - positional_operand_count = gb_min(positional_operand_count, pt->param_count); + if (check_order_of_call_arguments(c, proc_type, call, show_error)) { + return CallArgumentError_OutOfOrderParameters; + } - for (isize i = 0; i < positional_operand_count; i++) { - ordered_operands[i] = positional_operands[i]; - visited[i] = true; + isize positional_operand_count = positional_operands.count; + if (variadic) { + positional_operand_count = gb_min(positional_operands.count, pt->variadic_index); + } else if (positional_operand_count > pt->param_count) { + err = CallArgumentError_TooManyArguments; + char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td"; + if (show_error) { + gbString proc_str = expr_to_string(ce->proc); + defer (gb_string_free(proc_str)); + error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count); } + return err; + } + positional_operand_count = gb_min(positional_operand_count, pt->param_count); - auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count); + for (isize i = 0; i < positional_operand_count; i++) { + ordered_operands[i] = positional_operands[i]; + visited[i] = true; + } - if (named_operands.count != 0) { - GB_ASSERT(ce->split_args->named.count == named_operands.count); - for_array(i, ce->split_args->named) { - Ast *arg = ce->split_args->named[i]; - Operand operand = named_operands[i]; + auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count); - ast_node(fv, FieldValue, arg); - if (fv->field->kind != Ast_Ident) { - if (show_error) { - gbString expr_str = expr_to_string(fv->field); - error(arg, "Invalid parameter name '%s' in procedure call", expr_str); - gb_string_free(expr_str); - } - err = CallArgumentError_InvalidFieldValue; - continue; - } - String name = fv->field->Ident.token.string; - isize param_index = lookup_procedure_parameter(pt, name); - if (param_index < 0) { - if (show_error) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); - } - err = CallArgumentError_ParameterNotFound; - continue; + if (named_operands.count != 0) { + GB_ASSERT(ce->split_args->named.count == named_operands.count); + for_array(i, ce->split_args->named) { + Ast *arg = ce->split_args->named[i]; + Operand operand = named_operands[i]; + + ast_node(fv, FieldValue, arg); + if (fv->field->kind != Ast_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error(arg, "Invalid parameter name '%s' in procedure call", expr_str); + gb_string_free(expr_str); } - if (visited[param_index]) { - if (show_error) { - error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); - } - err = CallArgumentError_DuplicateParameter; - continue; + err = CallArgumentError_InvalidFieldValue; + continue; + } + String name = fv->field->Ident.token.string; + isize param_index = lookup_procedure_parameter(pt, name); + if (param_index < 0) { + if (show_error) { + error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); } - Entity *e = pt->params->Tuple.variables[param_index]; - - check_assignment(c, &operand, e->type, str_lit("named argument")); - - visited[param_index] = true; - ordered_operands[param_index] = operand; - - err = CallArgumentError_DuplicateParameter; + err = CallArgumentError_ParameterNotFound; + continue; } - } - - if (variadic) { - if (visited[pt->variadic_index] && - positional_operand_count < positional_operands.count) { + if (visited[param_index]) { if (show_error) { - String name = pt->params->Tuple.variables[pt->variadic_index]->token.string; - error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name)); + error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); } err = CallArgumentError_DuplicateParameter; - } else { - visited[pt->variadic_index] = true; - - if (vari_expand) { - GB_ASSERT(variadic_operands.count != 0); - ordered_operands[pt->variadic_index] = variadic_operands[0]; - } else { - AstFile *f = call->file(); - - // HACK(bill): this is an awful hack - Operand o = {}; - o.mode = Addressing_Value; - o.expr = ast_ident(f, make_token_ident("nil")); - o.expr->Ident.token.pos = ast_token(call).pos; - if (variadic_operands.count != 0) { - o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos; - - Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; - if (is_type_polymorphic(vt->type)) { - o.type = alloc_type_slice(default_type(variadic_operands[0].type)); - } else { - o.type = vt->type; - } - } else { - o.type = t_untyped_nil; - } - ordered_operands[pt->variadic_index] = o; - } + continue; } + Entity *e = pt->params->Tuple.variables[param_index]; - } - - for (Operand const &o : ordered_operands) { - if (o.mode != Addressing_Invalid) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - } + check_assignment(c, &operand, e->type, str_lit("named argument")); - for (isize i = 0; i < pt->param_count; i++) { - if (!visited[i]) { - Entity *e = pt->params->Tuple.variables[i]; - if (is_blank_ident(e->token)) { - continue; - } - if (e->kind == Entity_Variable) { - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - score += assign_score_function(1); - continue; - } - } + visited[param_index] = true; + ordered_operands[param_index] = operand; - if (show_error) { - if (e->kind == Entity_TypeName) { - error(call, "Type parameter '%.*s' is missing in procedure call", - LIT(e->token.string)); - } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { - // Ignore - } else { - gbString str = type_to_string(e->type); - error(call, "Parameter '%.*s' of type '%s' is missing in procedure call", - LIT(e->token.string), str); - gb_string_free(str); - } - } - err = CallArgumentError_ParameterMissing; - } + err = CallArgumentError_DuplicateParameter; } + } - if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) { - err = CallArgumentError_None; - - if (variadic) { - GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0); - Type *t = pt->params->Tuple.variables[0]->type; - if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); - err = CallArgumentError_AmbiguousPolymorphicVariadic; - } + if (variadic) { + if (visited[pt->variadic_index] && + positional_operand_count < positional_operands.count) { + if (show_error) { + String name = pt->params->Tuple.variables[pt->variadic_index]->token.string; + error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name)); } + err = CallArgumentError_DuplicateParameter; } else { - if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) { - PolyProcData poly_proc_data = {}; - if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, call, &poly_proc_data)) { - gen_entity = poly_proc_data.gen_entity; - Type *gept = base_type(gen_entity->type); - GB_ASSERT(is_type_proc(gept)); - final_proc_type = gen_entity->type; - pt = &gept->Proc; - - } else { - err = CallArgumentError_WrongTypes; - } - } - - for (isize i = 0; i < pt->param_count; i++) { - Operand *o = &ordered_operands[i]; - if (o->mode == Addressing_Invalid) { - continue; - } + visited[pt->variadic_index] = true; - Entity *e = pt->params->Tuple.variables[i]; - bool param_is_variadic = pt->variadic && pt->variadic_index == i; + if (vari_expand) { + GB_ASSERT(variadic_operands.count != 0); + ordered_operands[pt->variadic_index] = variadic_operands[0]; + } else { + AstFile *f = call->file(); - if (e->kind == Entity_TypeName) { - GB_ASSERT(pt->is_polymorphic); - if (o->mode != Addressing_Type) { - if (show_error) { - error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_WrongTypes; - } - if (are_types_identical(e->type, o->type)) { - score += assign_score_function(1); + // HACK(bill): this is an awful hack + Operand o = {}; + o.mode = Addressing_Value; + o.expr = ast_ident(f, make_token_ident("nil")); + o.expr->Ident.token.pos = ast_token(call).pos; + if (variadic_operands.count != 0) { + o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos; + + Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; + if (is_type_polymorphic(vt->type)) { + o.type = alloc_type_slice(default_type(variadic_operands[0].type)); } else { - score += assign_score_function(MAXIMUM_TYPE_DISTANCE); + o.type = vt->type; } } else { - i64 s = 0; - if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { - bool ok = false; - if (e->flags & EntityFlag_AnyInt) { - if (is_type_integer(e->type)) { - ok = check_is_castable_to(c, o, e->type); - } - } - if (ok) { - s = assign_score_function(MAXIMUM_TYPE_DISTANCE); - } else { - if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - err = CallArgumentError_WrongTypes; - } - - if (e->flags & EntityFlag_ConstInput) { - if (o->mode != Addressing_Constant) { - if (show_error) { - error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_NoneConstantParameter; - } - } - } else if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - score += s; - } - - if (o->mode == Addressing_Type && is_type_typeid(e->type)) { - add_type_info_type(c, o->type); - add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); - } else if (show_error && is_type_untyped(o->type)) { - update_untyped_expr_type(c, o->expr, e->type, true); + o.type = t_untyped_nil; } + ordered_operands[pt->variadic_index] = o; } } - if (variadic) { - Type *slice = pt->params->Tuple.variables[pt->variadic_index]->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - Type *t = elem; + } - if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); - err = CallArgumentError_AmbiguousPolymorphicVariadic; - } + for (Operand const &o : ordered_operands) { + if (o.mode != Addressing_Invalid) { + check_no_copy_assignment(o, str_lit("procedure call expression")); + } + } - for_array(operand_index, variadic_operands) { - Operand &o = variadic_operands[operand_index]; - if (vari_expand) { - t = slice; - if (operand_index > 0) { - if (show_error) { - error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end"); - } - if (data) { - data->score = score; - data->result_type = final_proc_type->Proc.results; - data->gen_entity = gen_entity; - } - return CallArgumentError_MultipleVariadicExpand; - } - } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("variadic argument")); - } - err = CallArgumentError_WrongTypes; - } else if (show_error) { - check_assignment(c, &o, t, str_lit("variadic argument")); - } - score += s; - if (is_type_any(elem)) { - add_type_info_type(c, o.type); - } - if (o.mode == Addressing_Type && is_type_typeid(t)) { - add_type_info_type(c, o.type); - add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); - } else if (show_error && is_type_untyped(o.type)) { - update_untyped_expr_type(c, o.expr, t, true); + for (isize i = 0; i < pt->param_count; i++) { + if (!visited[i]) { + Entity *e = pt->params->Tuple.variables[i]; + if (is_blank_ident(e->token)) { + continue; + } + if (e->kind == Entity_Variable) { + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + ordered_operands[i].mode = Addressing_Value; + ordered_operands[i].type = e->type; + ordered_operands[i].expr = e->Variable.param_value.original_ast_expr; + score += assign_score_function(1); + continue; } } - } - if (data) { - data->score = score; - data->result_type = final_proc_type->Proc.results; - data->gen_entity = gen_entity; - - - Ast *proc_lit = nullptr; - if (ce->proc->tav.value.kind == ExactValue_Procedure) { - Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure); - if (vp && vp->kind == Ast_ProcLit) { - proc_lit = vp; + if (show_error) { + if (e->kind == Entity_TypeName) { + error(call, "Type parameter '%.*s' is missing in procedure call", + LIT(e->token.string)); + } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { + // Ignore + } else { + gbString str = type_to_string(e->type); + error(call, "Parameter '%.*s' of type '%s' is missing in procedure call", + LIT(e->token.string), str); + gb_string_free(str); } } - if (proc_lit == nullptr) { - add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); - } + err = CallArgumentError_ParameterMissing; } - - return err; - } - - if (err) { - return err; - } - - auto operands = positional_operands; - TypeTuple *param_tuple = nullptr; - if (pt->params != nullptr) { - param_tuple = &pt->params->Tuple; } - if (operands.count == 0 && param_count_excluding_defaults == 0) { + if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) { err = CallArgumentError_None; if (variadic) { - GB_ASSERT(param_tuple != nullptr && param_tuple->variables.count > 0); - Type *t = param_tuple->variables[0]->type; + GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0); + Type *t = pt->params->Tuple.variables[0]->type; if (is_type_polymorphic(t)) { error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); err = CallArgumentError_AmbiguousPolymorphicVariadic; } } } else { - i32 error_code = 0; - if (operands.count < param_count_excluding_defaults) { - error_code = -1; - } else if (!variadic && operands.count > param_count) { - error_code = +1; - } - if (error_code != 0) { - err = CallArgumentError_TooManyArguments; - char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td"; - if (error_code < 0) { - err = CallArgumentError_TooFewArguments; - err_fmt = "Too few arguments for '%s', expected %td arguments, got %td"; - } + if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) { + PolyProcData poly_proc_data = {}; + if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, call, &poly_proc_data)) { + gen_entity = poly_proc_data.gen_entity; + Type *gept = base_type(gen_entity->type); + GB_ASSERT(is_type_proc(gept)); + final_proc_type = gen_entity->type; + pt = &gept->Proc; - if (show_error) { - gbString proc_str = expr_to_string(ce->proc); - defer (gb_string_free(proc_str)); - error(call, err_fmt, proc_str, param_count_excluding_defaults, operands.count); - - #if 0 - error_line("\t"); - for_array(i, operands) { - if (i > 0) { - error_line(", "); - } - gbString s = expr_to_string(operands[i].expr); - error_line("%s", s); - gb_string_free(s); - } - error_line("\n"); - #endif - } - } else { - // NOTE(bill): Generate the procedure type for this generic instance - if (pt->is_polymorphic && !pt->is_poly_specialized) { - PolyProcData poly_proc_data = {}; - if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &operands, call, &poly_proc_data)) { - gen_entity = poly_proc_data.gen_entity; - GB_ASSERT(is_type_proc(gen_entity->type)); - final_proc_type = gen_entity->type; - } else { - err = CallArgumentError_WrongTypes; - } + } else { + err = CallArgumentError_WrongTypes; } + } - GB_ASSERT(is_type_proc(final_proc_type)); - TypeProc *pt = &final_proc_type->Proc; - - GB_ASSERT(pt->params != nullptr); - auto sig_params = pt->params->Tuple.variables; - isize operand_index = 0; - isize max_operand_count = gb_min(param_count, operands.count); - for (; operand_index < max_operand_count; operand_index++) { - Entity *e = sig_params[operand_index]; - Type *t = e->type; - Operand o = operands[operand_index]; - if (o.expr != nullptr) { - call->viral_state_flags |= o.expr->viral_state_flags; - } + for (isize i = 0; i < pt->param_count; i++) { + Operand *o = &ordered_operands[i]; + if (o->mode == Addressing_Invalid) { + continue; + } - if (e->kind == Entity_TypeName) { - // GB_ASSERT(!variadic); - if (o.mode == Addressing_Invalid) { - continue; - } else if (o.mode != Addressing_Type) { - if (show_error) { - error(o.expr, "Expected a type for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_WrongTypes; - } + Entity *e = pt->params->Tuple.variables[i]; + bool param_is_variadic = pt->variadic && pt->variadic_index == i; - if (are_types_identical(e->type, o.type)) { - score += assign_score_function(1); - } else { - score += assign_score_function(MAXIMUM_TYPE_DISTANCE); + if (e->kind == Entity_TypeName) { + GB_ASSERT(pt->is_polymorphic); + if (o->mode != Addressing_Type) { + if (show_error) { + error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string)); } - - continue; + err = CallArgumentError_WrongTypes; } - - bool param_is_variadic = pt->variadic && pt->variadic_index == operand_index; - + if (are_types_identical(e->type, o->type)) { + score += assign_score_function(1); + } else { + score += assign_score_function(MAXIMUM_TYPE_DISTANCE); + } + } else { i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s, param_is_variadic)) { + if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { bool ok = false; if (e->flags & EntityFlag_AnyInt) { - if (is_type_integer(t)) { - ok = check_is_castable_to(c, &o, t); + if (is_type_integer(e->type)) { + ok = check_is_castable_to(c, o, e->type); } } if (ok) { s = assign_score_function(MAXIMUM_TYPE_DISTANCE); } else { if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - // TODO(bill, 2021-05-05): Is this incorrect logic to only fail if there is ambiguity for definite? - if (o.mode == Addressing_Invalid) { - err = CallArgumentError_WrongTypes; + check_assignment(c, o, e->type, str_lit("procedure argument")); } + err = CallArgumentError_WrongTypes; } - } else if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - score += s; - if (e->flags & EntityFlag_ConstInput) { - if (o.mode != Addressing_Constant) { - if (show_error) { - error(o.expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); + if (e->flags & EntityFlag_ConstInput) { + if (o->mode != Addressing_Constant) { + if (show_error) { + error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); + } + err = CallArgumentError_NoneConstantParameter; } - err = CallArgumentError_NoneConstantParameter; } + } else if (show_error) { + check_assignment(c, o, e->type, str_lit("procedure argument")); } + score += s; + } - if (o.mode == Addressing_Type && is_type_typeid(e->type)) { - add_type_info_type(c, o.type); - add_type_and_value(c, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type)); - } else if (show_error && is_type_untyped(o.type)) { - update_untyped_expr_type(c, o.expr, t, true); - } - + if (o->mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o->type); + add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + } else if (show_error && is_type_untyped(o->type)) { + update_untyped_expr_type(c, o->expr, e->type, true); } + } + } - if (variadic) { - bool variadic_expand = false; - Type *slice = sig_params[param_count]->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - Type *t = elem; + if (variadic) { + Type *slice = pt->params->Tuple.variables[pt->variadic_index]->type; + GB_ASSERT(is_type_slice(slice)); + Type *elem = base_type(slice)->Slice.elem; + Type *t = elem; - if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); - err = CallArgumentError_AmbiguousPolymorphicVariadic; - } + if (is_type_polymorphic(t)) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + err = CallArgumentError_AmbiguousPolymorphicVariadic; + } - for (; operand_index < operands.count; operand_index++) { - Operand o = operands[operand_index]; - if (vari_expand) { - variadic_expand = true; - t = slice; - if (operand_index != param_count) { - if (show_error) { - error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end"); - } - if (data) { - data->score = score; - data->result_type = final_proc_type->Proc.results; - data->gen_entity = gen_entity; - } - return CallArgumentError_MultipleVariadicExpand; - } - } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - err = CallArgumentError_WrongTypes; - } else if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); + for_array(operand_index, variadic_operands) { + Operand &o = variadic_operands[operand_index]; + if (vari_expand) { + t = slice; + if (operand_index > 0) { + if (show_error) { + error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end"); } - score += s; - if (is_type_any(elem)) { - add_type_info_type(c, o.type); - } - if (o.mode == Addressing_Type && is_type_typeid(t)) { - add_type_info_type(c, o.type); - add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); - } else if (show_error && is_type_untyped(o.type)) { - update_untyped_expr_type(c, o.expr, t, true); + if (data) { + data->score = score; + data->result_type = final_proc_type->Proc.results; + data->gen_entity = gen_entity; } + return CallArgumentError_MultipleVariadicExpand; } } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("variadic argument")); + } + err = CallArgumentError_WrongTypes; + } else if (show_error) { + check_assignment(c, &o, t, str_lit("variadic argument")); + } + score += s; + if (is_type_any(elem)) { + add_type_info_type(c, o.type); + } + if (o.mode == Addressing_Type && is_type_typeid(t)) { + add_type_info_type(c, o.type); + add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); + } else if (show_error && is_type_untyped(o.type)) { + update_untyped_expr_type(c, o.expr, t, true); + } } } @@ -5917,193 +5694,6 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { return ce->args[0]->kind == Ast_FieldValue; } -gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) { - auto operands = positional_operands; - ast_node(ce, CallExpr, call); - GB_ASSERT(is_type_proc(proc_type)); - proc_type = base_type(proc_type); - TypeProc *pt = &proc_type->Proc; - - i64 score = 0; - bool show_error = show_error_mode == CallArgumentMode_ShowErrors; - CallArgumentError err = CallArgumentError_None; - - TEMPORARY_ALLOCATOR_GUARD(); - - isize param_count = pt->param_count; - bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); - auto ordered_operands = array_make(temporary_allocator(), param_count); - defer ({ - for (Operand const &o : ordered_operands) { - if (o.expr != nullptr) { - call->viral_state_flags |= o.expr->viral_state_flags; - } - } - }); - - if (check_order_of_call_arguments(c, proc_type, call, show_error)) { - return CallArgumentError_OutOfOrderParameters; - } - - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - ast_node(fv, FieldValue, arg); - if (fv->field->kind != Ast_Ident) { - if (show_error) { - gbString expr_str = expr_to_string(fv->field); - error(arg, "Invalid parameter name '%s' in procedure call", expr_str); - gb_string_free(expr_str); - } - err = CallArgumentError_InvalidFieldValue; - continue; - } - String name = fv->field->Ident.token.string; - isize index = lookup_procedure_parameter(pt, name); - if (index < 0) { - if (show_error) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); - } - err = CallArgumentError_ParameterNotFound; - continue; - } - if (visited[index]) { - if (show_error) { - error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); - } - err = CallArgumentError_DuplicateParameter; - continue; - } - - visited[index] = true; - ordered_operands[index] = operands[i]; - } - - // NOTE(bill): Check for default values and missing parameters - isize param_count_to_check = param_count; - if (pt->variadic) { - param_count_to_check--; - } - for (isize i = 0; i < param_count_to_check; i++) { - if (!visited[i]) { - Entity *e = pt->params->Tuple.variables[i]; - if (is_blank_ident(e->token)) { - continue; - } - if (e->kind == Entity_Variable) { - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - score += assign_score_function(1); - continue; - } - } - - if (show_error) { - if (e->kind == Entity_TypeName) { - error(call, "Type parameter '%.*s' is missing in procedure call", - LIT(e->token.string)); - } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { - // Ignore - } else { - gbString str = type_to_string(e->type); - error(call, "Parameter '%.*s' of type '%s' is missing in procedure call", - LIT(e->token.string), str); - gb_string_free(str); - } - } - err = CallArgumentError_ParameterMissing; - } - } - - Entity *gen_entity = nullptr; - if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) { - PolyProcData poly_proc_data = {}; - if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, call, &poly_proc_data)) { - gen_entity = poly_proc_data.gen_entity; - Type *gept = base_type(gen_entity->type); - GB_ASSERT(is_type_proc(gept)); - proc_type = gept; - pt = &gept->Proc; - } else { - err = CallArgumentError_WrongTypes; - } - } - - - for (isize i = 0; i < param_count; i++) { - Entity *e = pt->params->Tuple.variables[i]; - Operand *o = &ordered_operands[i]; - bool param_is_variadic = pt->variadic && pt->variadic_index == i; - - - if (o->mode == Addressing_Invalid) { - if (param_is_variadic) { - Type *slice = e->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - if (is_type_polymorphic(elem)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); - err = CallArgumentError_AmbiguousPolymorphicVariadic; - return err; - } - } - continue; - } - - if (e->kind == Entity_TypeName) { - GB_ASSERT(pt->is_polymorphic); - if (o->mode != Addressing_Type) { - if (show_error) { - error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_WrongTypes; - } - if (are_types_identical(e->type, o->type)) { - score += assign_score_function(1); - } else { - score += assign_score_function(MAXIMUM_TYPE_DISTANCE); - } - } else { - i64 s = 0; - if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { - bool ok = false; - if (ok) { - s = assign_score_function(MAXIMUM_TYPE_DISTANCE); - } else { - if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - err = CallArgumentError_WrongTypes; - } - - if (e->flags & EntityFlag_ConstInput) { - if (o->mode != Addressing_Constant) { - if (show_error) { - error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_NoneConstantParameter; - } - } - } else if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - score += s; - } - - if (o->mode == Addressing_Type && is_type_typeid(e->type)) { - add_type_info_type(c, o->type); - add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); - } - } - - if (data) { - data->score = score; - data->result_type = pt->results; - data->gen_entity = gen_entity; - add_type_and_value(c, ce->proc, Addressing_Value, proc_type, {}); - } - - return err; -} - gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) { Entity **lhs = nullptr; isize lhs_count = -1; @@ -7014,568 +6604,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex return data; } - -gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Ast *call) { - if (operand->mode == Addressing_ProcGroup) { - Array procs = proc_group_entities(c, *operand); - bool all_non_poly = true; - for (Entity *e : procs) { - if (is_type_polymorphic(e->type)) { - all_non_poly = false; - break; - } - } - if (true) { - return check_call_arguments_new_and_improved(c, operand, call); - } - } else { - return check_call_arguments_new_and_improved(c, operand, call); - } - - ast_node(ce, CallExpr, call); - - CallArgumentCheckerType *call_checker = check_call_arguments_internal; - Array operands = {}; - defer (array_free(&operands)); - - Type *result_type = t_invalid; - Type *proc_type = base_type(operand->type); - - Slice const &args = ce->args; - if (is_call_expr_field_value(ce)) { - Type *ptype = nullptr; - bool single_case = true; - - if (operand->mode == Addressing_ProcGroup) { - single_case = false; - Array procs = proc_group_entities(c, *operand); - if (procs.count == 1) { - ptype = procs[0]->type; - single_case = true; - } - } else { - ptype = proc_type; - } - - if (check_order_of_call_arguments(c, ptype, call, true)) { - CallArgumentData data = {}; - data.result_type = t_invalid; - if (ptype && is_type_proc(ptype) && !is_type_polymorphic(ptype)) { - data.result_type = reduce_tuple_to_single_type(ptype->Proc.results); - } - return data; - } - - call_checker = check_named_call_arguments; - - operands = array_make(heap_allocator(), args.count); - - // NOTE(bill): This is give type hints for the named parameters - // in order to improve the type inference system - - StringMap type_hint_map = {}; // Key: String - string_map_init(&type_hint_map, 2*args.count); - defer (string_map_destroy(&type_hint_map)); - - - if (single_case) { - Type *bptype = base_type(ptype); - if (is_type_proc(bptype)) { - TypeProc *pt = &bptype->Proc; - TypeTuple *param_tuple = nullptr; - if (pt->params != nullptr) { - param_tuple = &pt->params->Tuple; - } - if (param_tuple != nullptr) { - for (Entity *e : param_tuple->variables) { - if (is_blank_ident(e->token)) { - continue; - } - string_map_set(&type_hint_map, e->token.string, e->type); - } - } - } - } else { - Array procs = proc_group_entities(c, *operand); - for (Entity *proc : procs) { - Type *proc_type = base_type(proc->type); - if (is_type_proc(proc_type)) { - TypeProc *pt = &proc_type->Proc; - TypeTuple *param_tuple = nullptr; - if (pt->params != nullptr) { - param_tuple = &pt->params->Tuple; - } - if (param_tuple == nullptr) { - continue; - } - for (Entity *e : param_tuple->variables) { - if (is_blank_ident(e->token)) { - continue; - } - StringHashKey key = string_hash_string(e->token.string); - Type **found = string_map_get(&type_hint_map, key); - if (found) { - Type *t = *found; - if (t == nullptr) { - // NOTE(bill): Ambiguous named parameter across all types - continue; - } - if (are_types_identical(t, e->type)) { - // NOTE(bill): No need to set again - } else { - // NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr - string_map_set(&type_hint_map, key, cast(Type *)nullptr); - } - } else { - string_map_set(&type_hint_map, key, e->type); - } - } - } - } - - } - - - for_array(i, args) { - Ast *arg = args[i]; - ast_node(fv, FieldValue, arg); - Ast *field = fv->field; - - Type *type_hint = nullptr; - - if (field != nullptr && field->kind == Ast_Ident) { - String key = field->Ident.token.string; - Type **found = string_map_get(&type_hint_map, key); - if (found) { - type_hint = *found; - } - } - check_expr_or_type(c, &operands[i], fv->value, type_hint); - } - } else { - operands = array_make(heap_allocator(), 0, 2*args.count); - Entity **lhs = nullptr; - isize lhs_count = -1; - bool is_variadic = false; - if (proc_type != nullptr && is_type_proc(proc_type)) { - lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); - } - if (operand->mode != Addressing_ProcGroup) { - check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); - } - } - - for (Operand const &o : operands) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - - if (operand->mode == Addressing_ProcGroup) { - check_entity_decl(c, operand->proc_group, nullptr, nullptr); - - auto procs = proc_group_entities_cloned(c, *operand); - - if (procs.count > 1) { - isize max_arg_count = args.count; - for (Ast *arg : args) { - // NOTE(bill): The only thing that may have multiple values - // will be a call expression (assuming `or_return` and `()` will be stripped) - arg = strip_or_return_expr(arg); - if (arg && arg->kind == Ast_CallExpr) { - max_arg_count = ISIZE_MAX; - break; - } - } - - for (isize proc_index = 0; proc_index < procs.count; /**/) { - Entity *proc = procs[proc_index]; - Type *pt = base_type(proc->type); - if (!(pt != nullptr && is_type_proc(pt))) { - proc_index++; - continue; - } - - isize param_count = 0; - isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(pt, ¶m_count); - - if (param_count_excluding_defaults > max_arg_count) { - array_unordered_remove(&procs, proc_index); - } else { - proc_index++; - } - } - } - - if (procs.count == 1) { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - - Entity *e = procs[0]; - - Entity **lhs = nullptr; - isize lhs_count = -1; - bool is_variadic = false; - lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); - check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); - - Array named_operands = {}; - CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, e->type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); - if (err != CallArgumentError_None) { - // handle error - } - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - } - return data; - } - - - Entity **lhs = nullptr; - isize lhs_count = -1; - - { - // NOTE(bill, 2019-07-13): This code is used to improve the type inference for procedure groups - // where the same positional parameter has the same type value (and ellipsis) - bool proc_arg_count_all_equal = true; - isize proc_arg_count = -1; - for (Entity *p : procs) { - Type *pt = base_type(p->type); - if (pt != nullptr && is_type_proc(pt)) { - if (proc_arg_count < 0) { - proc_arg_count = pt->Proc.param_count; - } else { - if (proc_arg_count != pt->Proc.param_count) { - proc_arg_count_all_equal = false; - break; - } - } - } - } - - - - if (proc_arg_count >= 0 && proc_arg_count_all_equal) { - lhs_count = proc_arg_count; - if (lhs_count > 0) { - lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count); - for (isize param_index = 0; param_index < lhs_count; param_index++) { - Entity *e = nullptr; - for (Entity *p : procs) { - Type *pt = base_type(p->type); - if (pt != nullptr && is_type_proc(pt)) { - if (e == nullptr) { - e = pt->Proc.params->Tuple.variables[param_index]; - } else { - Entity *f = pt->Proc.params->Tuple.variables[param_index]; - if (e == f) { - continue; - } - if (are_types_identical(e->type, f->type)) { - bool ee = (e->flags & EntityFlag_Ellipsis) != 0; - bool fe = (f->flags & EntityFlag_Ellipsis) != 0; - if (ee == fe) { - continue; - } - } - // NOTE(bill): Entities are not close enough to be used - e = nullptr; - break; - } - } - } - lhs[param_index] = e; - } - } - } - } - - - check_unpack_arguments(c, lhs, lhs_count, &operands, args, UnpackFlag_None); - - if (lhs != nullptr) { - gb_free(heap_allocator(), lhs); - } - - auto valids = array_make(heap_allocator(), 0, procs.count); - defer (array_free(&valids)); - - auto proc_entities = array_make(heap_allocator(), 0, procs.count*2 + 1); - defer (array_free(&proc_entities)); - for (Entity *proc : procs) { - array_add(&proc_entities, proc); - } - - - gbString expr_name = expr_to_string(operand->expr); - defer (gb_string_free(expr_name)); - - for_array(i, procs) { - Entity *p = procs[i]; - Type *pt = base_type(p->type); - if (pt != nullptr && is_type_proc(pt)) { - CallArgumentError err = CallArgumentError_None; - CallArgumentData data = {}; - CheckerContext ctx = *c; - - ctx.no_polymorphic_errors = true; - ctx.allow_polymorphic_types = is_type_polymorphic(pt); - ctx.hide_polymorphic_errors = true; - - Array named_operands = {}; - err = call_checker(&ctx, call, pt, p, operands, named_operands, CallArgumentMode_NoErrors, &data); - if (err != CallArgumentError_None) { - continue; - } - isize index = i; - - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - if (!evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) { - continue; - } - - array_add(&proc_entities, data.gen_entity); - index = proc_entities.count-1; - } - - ValidIndexAndScore item = {}; - item.index = index; - item.score = data.score; - array_add(&valids, item); - } - } - - if (valids.count > 1) { - gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp); - i64 best_score = valids[0].score; - Entity *best_entity = proc_entities[valids[0].index]; - GB_ASSERT(best_entity != nullptr); - for (isize i = 1; i < valids.count; i++) { - if (best_score > valids[i].score) { - valids.count = i; - break; - } - if (best_entity == proc_entities[valids[i].index]) { - valids.count = i; - break; - } - } - } - - - if (valids.count == 0) { - begin_error_block(); - defer (end_error_block()); - - error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name); - if (operands.count == 0) { - error_line("\tNo given arguments\n"); - } else { - error_line("\tGiven argument types: ("); - for_array(i, operands) { - Operand o = operands[i]; - if (i > 0) error_line(", "); - gbString type = type_to_string(o.type); - defer (gb_string_free(type)); - error_line("%s", type); - } - error_line(")\n"); - } - - if (procs.count > 0) { - error_line("Did you mean to use one of the following:\n"); - } - for (Entity *proc : procs) { - TokenPos pos = proc->token.pos; - Type *t = base_type(proc->type); - if (t == t_invalid) continue; - GB_ASSERT(t->kind == Type_Proc); - gbString pt; - defer (gb_string_free(pt)); - if (t->Proc.node != nullptr) { - pt = expr_to_string(t->Proc.node); - } else { - pt = type_to_string(t); - } - String prefix = {}; - String prefix_sep = {}; - if (proc->pkg) { - prefix = proc->pkg->name; - prefix_sep = str_lit("."); - } - String name = proc->token.string; - - char const *sep = "::"; - if (proc->kind == Entity_Variable) { - sep = ":="; - } - error_line("\t%.*s%.*s%.*s %s %s at %s\n", LIT(prefix), LIT(prefix_sep), LIT(name), sep, pt, token_pos_to_string(pos)); - } - if (procs.count > 0) { - error_line("\n"); - } - - result_type = t_invalid; - } else if (valids.count > 1) { - begin_error_block(); - defer (end_error_block()); - - error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name); - error_line("\tGiven argument types: ("); - for_array(i, operands) { - Operand o = operands[i]; - if (i > 0) error_line(", "); - gbString type = type_to_string(o.type); - defer (gb_string_free(type)); - error_line("%s", type); - } - error_line(")\n"); - - for (isize i = 0; i < valids.count; i++) { - Entity *proc = proc_entities[valids[i].index]; - GB_ASSERT(proc != nullptr); - TokenPos pos = proc->token.pos; - Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc); - gbString pt = nullptr; - defer (gb_string_free(pt)); - if (t->Proc.node != nullptr) { - pt = expr_to_string(t->Proc.node); - } else { - pt = type_to_string(t); - } - String name = proc->token.string; - char const *sep = "::"; - if (proc->kind == Entity_Variable) { - sep = ":="; - } - error_line("\t%.*s %s %s ", LIT(name), sep, pt); - if (proc->decl_info->proc_lit != nullptr) { - GB_ASSERT(proc->decl_info->proc_lit->kind == Ast_ProcLit); - auto *pl = &proc->decl_info->proc_lit->ProcLit; - if (pl->where_token.kind != Token_Invalid) { - error_line("\n\t\twhere "); - for_array(j, pl->where_clauses) { - Ast *clause = pl->where_clauses[j]; - if (j != 0) { - error_line("\t\t "); - } - gbString str = expr_to_string(clause); - error_line("%s", str); - gb_string_free(str); - - if (j != pl->where_clauses.count-1) { - error_line(","); - } - } - error_line("\n\t"); - } - } - error_line("at %s\n", token_pos_to_string(pos)); - } - result_type = t_invalid; - } else { - GB_ASSERT(valids.count == 1); - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - - Entity *e = proc_entities[valids[0].index]; - GB_ASSERT(e != nullptr); - - Array named_operands = {}; - - proc_type = e->type; - CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); - gb_unused(err); - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - } - - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - } - return data; - } - } else { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - - Entity *e = entity_of_node(ident); - - Array named_operands = {}; - - CallArgumentData data = {}; - CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data); - gb_unused(err); - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - } - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - } - return data; - } - - - CallArgumentData data = {}; - data.result_type = t_invalid; - return data; -} - - gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_name) { if (!is_type_polymorphic_record(t)) { return -1; @@ -8136,7 +7164,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - CallArgumentData data = check_call_arguments(c, operand, call); + CallArgumentData data = check_call_arguments_new_and_improved(c, operand, call); Type *result_type = data.result_type; gb_zero_item(operand); operand->expr = call; -- cgit v1.2.3 From fb756e346380288ba2a1e14150d9f99619c4c6e8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 21:02:57 +0100 Subject: Correct procedure group handling --- src/check_expr.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 05fd51119..48fdfe871 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5447,6 +5447,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } } + isize dummy_argument_count = 0; + bool actually_variadic = false; + if (variadic) { if (visited[pt->variadic_index] && positional_operand_count < positional_operands.count) { @@ -5461,6 +5464,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A if (vari_expand) { GB_ASSERT(variadic_operands.count != 0); ordered_operands[pt->variadic_index] = variadic_operands[0]; + actually_variadic = true; } else { AstFile *f = call->file(); @@ -5470,6 +5474,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A o.expr = ast_ident(f, make_token_ident("nil")); o.expr->Ident.token.pos = ast_token(call).pos; if (variadic_operands.count != 0) { + actually_variadic = true; o.expr->Ident.token.pos = ast_token(variadic_operands[0].expr).pos; Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; @@ -5479,6 +5484,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A o.type = vt->type; } } else { + dummy_argument_count += 1; o.type = t_untyped_nil; } ordered_operands[pt->variadic_index] = o; @@ -5504,6 +5510,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A ordered_operands[i].mode = Addressing_Value; ordered_operands[i].type = e->type; ordered_operands[i].expr = e->Variable.param_value.original_ast_expr; + + dummy_argument_count += 1; score += assign_score_function(1); continue; } @@ -5603,7 +5611,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else if (show_error) { check_assignment(c, o, e->type, str_lit("procedure argument")); } - score += s; + if (!param_is_variadic) { + score += s; + } } if (o->mode == Addressing_Type && is_type_typeid(e->type)) { @@ -6070,9 +6080,10 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch CallArgumentError err = check_call_arguments_internal(c, call, e->type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); if (err != CallArgumentError_None) { - // handle error + } + Type *proc_type = base_type(operand->type); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; @@ -6086,8 +6097,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch if (proc_type && proc_type->kind == Type_Proc) { data.result_type = proc_type->Proc.results; add_type_and_value(c, operand->expr, operand->mode, proc_type, operand->value); - } else if (err == CallArgumentError_None) { - data.result_type = nullptr; } if (data.gen_entity != nullptr) { @@ -6108,6 +6117,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } + return data; } @@ -6419,6 +6429,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; add_entity_use(c, ident, entity_to_use); if (entity_to_use != nullptr) { + proc_type = base_type(entity_to_use->type); update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } @@ -6441,6 +6452,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); } } + + if (is_type_proc(proc_type)) { + data.result_type = proc_type->Proc.results; + } + return data; } -- cgit v1.2.3 From 2a002c3882ab0c82d5d9553da7926532e832ef4e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 22:55:33 +0100 Subject: Fix scoring for untyped ternary expressions --- src/check_expr.cpp | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 48fdfe871..2e5b23e78 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -700,23 +700,34 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } return -1; } - if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedRune) { - if (is_type_integer(dst) || is_type_rune(dst)) { - if (is_type_typed(type)) { - return 2; + if (src->kind == Type_Basic) { + switch (src->Basic.kind) { + case Basic_UntypedRune: + if (is_type_integer(dst) || is_type_rune(dst)) { + if (is_type_typed(type)) { + return 2; + } + return 1; } - return 1; - } - return -1; - } - if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) { - if (is_type_boolean(dst)) { - if (is_type_typed(type)) { - return 2; + return -1; + case Basic_UntypedBool: + if (is_type_boolean(dst)) { + if (is_type_typed(type)) { + return 2; + } + return 1; } - return 1; + return -1; + case Basic_UntypedString: + if (is_type_string(dst) || is_type_cstring(dst)) { + if (is_type_typed(type)) { + return 2; + } + return 1; + } + return -1; } - return -1; + } } } @@ -5461,9 +5472,12 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else { visited[pt->variadic_index] = true; + Operand *variadic_operand = &ordered_operands[pt->variadic_index]; + if (vari_expand) { GB_ASSERT(variadic_operands.count != 0); - ordered_operands[pt->variadic_index] = variadic_operands[0]; + *variadic_operand = variadic_operands[0]; + variadic_operand->type = default_type(variadic_operand->type); actually_variadic = true; } else { AstFile *f = call->file(); @@ -5487,7 +5501,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A dummy_argument_count += 1; o.type = t_untyped_nil; } - ordered_operands[pt->variadic_index] = o; + *variadic_operand = o; } } -- cgit v1.2.3 From 09f366bec72087fb8ed835cda6d2b8cc115627e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 00:03:56 +0100 Subject: Correct purely named argument handling --- src/check_expr.cpp | 181 +++++++++++++++++---------------- src/llvm_backend_proc.cpp | 250 +--------------------------------------------- 2 files changed, 99 insertions(+), 332 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2e5b23e78..5b1f1a73c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -676,6 +676,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand return 1; } break; + case Basic_UntypedString: + if (is_type_string(dst)) { + return 1; + } + break; case Basic_UntypedFloat: if (is_type_float(dst)) { return 1; @@ -701,33 +706,48 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand return -1; } if (src->kind == Type_Basic) { + i64 score = -1; switch (src->Basic.kind) { case Basic_UntypedRune: if (is_type_integer(dst) || is_type_rune(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + score = 1; } - return -1; - case Basic_UntypedBool: - if (is_type_boolean(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + break; + case Basic_UntypedInteger: + if (is_type_integer(dst) || is_type_rune(dst)) { + score = 1; } - return -1; + break; case Basic_UntypedString: - if (is_type_string(dst) || is_type_cstring(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + if (is_type_string(dst)) { + score = 1; } - return -1; + break; + case Basic_UntypedFloat: + if (is_type_float(dst)) { + score = 1; + } + break; + case Basic_UntypedComplex: + if (is_type_complex(dst)) { + score = 1; + } + if (is_type_quaternion(dst)) { + score = 2; + } + break; + case Basic_UntypedQuaternion: + if (is_type_quaternion(dst)) { + score = 1; + } + break; } - + if (score > 0) { + if (is_type_typed(dst)) { + score += 1; + } + } + return score; } } } @@ -5447,14 +5467,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A err = CallArgumentError_DuplicateParameter; continue; } - Entity *e = pt->params->Tuple.variables[param_index]; - - check_assignment(c, &operand, e->type, str_lit("named argument")); visited[param_index] = true; ordered_operands[param_index] = operand; - - err = CallArgumentError_DuplicateParameter; } } @@ -5469,7 +5484,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name)); } err = CallArgumentError_DuplicateParameter; - } else { + } else if (!visited[pt->variadic_index]) { visited[pt->variadic_index] = true; Operand *variadic_operand = &ordered_operands[pt->variadic_index]; @@ -5548,6 +5563,52 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } } + auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error) -> i64 { + i64 s = 0; + if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic)) { + bool ok = false; + if (e && e->flags & EntityFlag_AnyInt) { + if (is_type_integer(param_type)) { + ok = check_is_castable_to(c, o, param_type); + } + } + if (ok) { + s = assign_score_function(MAXIMUM_TYPE_DISTANCE); + } else { + if (show_error) { + check_assignment(c, o, param_type, str_lit("procedure argument")); + } + err = CallArgumentError_WrongTypes; + } + + } else if (show_error) { + check_assignment(c, o, param_type, str_lit("procedure argument")); + } + + if (e && e->flags & EntityFlag_ConstInput) { + if (o->mode != Addressing_Constant) { + if (show_error) { + error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); + } + err = CallArgumentError_NoneConstantParameter; + } + } + + + if (!err && is_type_any(param_type)) { + add_type_info_type(c, o->type); + } + if (o->mode == Addressing_Type && is_type_typeid(param_type)) { + add_type_info_type(c, o->type); + add_type_and_value(c, o->expr, Addressing_Value, param_type, exact_value_typeid(o->type)); + } else if (show_error && is_type_untyped(o->type)) { + update_untyped_expr_type(c, o->expr, param_type, true); + } + + return s; + }; + + if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) { err = CallArgumentError_None; @@ -5555,7 +5616,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0); Type *t = pt->params->Tuple.variables[0]->type; if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); + if (show_error) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); + } err = CallArgumentError_AmbiguousPolymorphicVariadic; } } @@ -5596,46 +5659,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else { score += assign_score_function(MAXIMUM_TYPE_DISTANCE); } - } else { - i64 s = 0; - if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) { - bool ok = false; - if (e->flags & EntityFlag_AnyInt) { - if (is_type_integer(e->type)) { - ok = check_is_castable_to(c, o, e->type); - } - } - if (ok) { - s = assign_score_function(MAXIMUM_TYPE_DISTANCE); - } else { - if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - err = CallArgumentError_WrongTypes; - } - - if (e->flags & EntityFlag_ConstInput) { - if (o->mode != Addressing_Constant) { - if (show_error) { - error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string)); - } - err = CallArgumentError_NoneConstantParameter; - } - } - } else if (show_error) { - check_assignment(c, o, e->type, str_lit("procedure argument")); - } - if (!param_is_variadic) { - score += s; - } + continue; } - if (o->mode == Addressing_Type && is_type_typeid(e->type)) { - add_type_info_type(c, o->type); - add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); - } else if (show_error && is_type_untyped(o->type)) { - update_untyped_expr_type(c, o->expr, e->type, true); + if (param_is_variadic) { + continue; } + + score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error); } } @@ -5651,12 +5682,12 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } for_array(operand_index, variadic_operands) { - Operand &o = variadic_operands[operand_index]; + Operand *o = &variadic_operands[operand_index]; if (vari_expand) { t = slice; if (operand_index > 0) { if (show_error) { - error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end"); + error(o->expr, "'..' in a variadic procedure can only have one variadic argument at the end"); } if (data) { data->score = score; @@ -5666,25 +5697,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A return CallArgumentError_MultipleVariadicExpand; } } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("variadic argument")); - } - err = CallArgumentError_WrongTypes; - } else if (show_error) { - check_assignment(c, &o, t, str_lit("variadic argument")); - } - score += s; - if (is_type_any(elem)) { - add_type_info_type(c, o.type); - } - if (o.mode == Addressing_Type && is_type_typeid(t)) { - add_type_info_type(c, o.type); - add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type)); - } else if (show_error && is_type_untyped(o.type)) { - update_untyped_expr_type(c, o.expr, t, true); - } + score += eval_param_and_score(c, o, t, err, true, nullptr, show_error); } } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b7ee88804..fc58d584e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3336,253 +3336,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - if (ce->split_args) { - return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args); - } - - if (is_call_expr_field_value(ce)) { - auto args = array_make(permanent_allocator(), pt->param_count); - - for_array(arg_index, ce->args) { - Ast *arg = ce->args[arg_index]; - ast_node(fv, FieldValue, arg); - GB_ASSERT(fv->field->kind == Ast_Ident); - String name = fv->field->Ident.token.string; - isize index = lookup_procedure_parameter(pt, name); - GB_ASSERT(index >= 0); - TypeAndValue tav = type_and_value_of_expr(fv->value); - if (tav.mode == Addressing_Type) { - args[index] = lb_const_nil(m, tav.type); - } else { - args[index] = lb_build_expr(p, fv->value); - } - } - TypeTuple *params = &pt->params->Tuple; - for (isize i = 0; i < args.count; i++) { - Entity *e = params->variables[i]; - if (e->kind == Entity_TypeName) { - args[i] = lb_const_nil(m, e->type); - } else if (e->kind == Entity_Constant) { - continue; - } else { - GB_ASSERT(e->kind == Entity_Variable); - if (args[i].value == nullptr) { - args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } else if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) { - args[i] = lb_typeid(p->module, args[i].type); - } else { - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - } - - for (isize i = 0; i < args.count; i++) { - Entity *e = params->variables[i]; - if (args[i].type == nullptr) { - continue; - } else if (is_type_untyped_uninit(args[i].type)) { - args[i] = lb_const_undef(m, e->type); - } else if (is_type_untyped_nil(args[i].type)) { - args[i] = lb_const_nil(m, e->type); - } - } - - return lb_emit_call(p, value, args, ce->inlining); - } - - isize arg_index = 0; - - isize arg_count = 0; - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - if (arg->kind == Ast_FieldValue) { - arg = arg->FieldValue.value; - } - TypeAndValue tav = type_and_value_of_expr(arg); - GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode); - GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg)); - Type *at = tav.type; - if (is_type_tuple(at)) { - arg_count += at->Tuple.variables.count; - } else { - arg_count++; - } - } - - isize param_count = 0; - if (pt->params) { - GB_ASSERT(pt->params->kind == Type_Tuple); - param_count = pt->params->Tuple.variables.count; - } - - auto args = array_make(permanent_allocator(), cast(isize)gb_max(param_count, arg_count)); - isize variadic_index = pt->variadic_index; - bool variadic = pt->variadic && variadic_index >= 0; - bool vari_expand = ce->ellipsis.pos.line != 0; - bool is_c_vararg = pt->c_vararg; - - String proc_name = {}; - if (p->entity != nullptr) { - proc_name = p->entity->token.string; - } - TokenPos pos = ast_token(ce->proc).pos; - - TypeTuple *param_tuple = nullptr; - if (pt->params) { - GB_ASSERT(pt->params->kind == Type_Tuple); - param_tuple = &pt->params->Tuple; - } - - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - TypeAndValue arg_tv = type_and_value_of_expr(arg); - if (arg_tv.mode == Addressing_Type) { - args[arg_index++] = lb_const_nil(m, arg_tv.type); - } else { - lbValue a = lb_build_expr(p, arg); - Type *at = a.type; - if (at->kind == Type_Tuple) { - lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value); - if (tf) { - for_array(j, tf->values) { - args[arg_index++] = tf->values[j]; - } - } else { - for_array(j, at->Tuple.variables) { - lbValue v = lb_emit_struct_ev(p, a, cast(i32)j); - args[arg_index++] = v; - } - } - } else { - args[arg_index++] = a; - } - } - } - - - if (param_count > 0) { - GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count); - GB_ASSERT(param_count < 1000000); - - if (arg_count < param_count) { - isize end = cast(isize)param_count; - if (variadic) { - end = variadic_index; - } - while (arg_index < end) { - Entity *e = param_tuple->variables[arg_index]; - GB_ASSERT(e->kind == Entity_Variable); - args[arg_index++] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } - } - - if (is_c_vararg) { - GB_ASSERT(variadic); - GB_ASSERT(!vari_expand); - isize i = 0; - for (; i < variadic_index; i++) { - Entity *e = param_tuple->variables[i]; - if (e->kind == Entity_Variable) { - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - Type *variadic_type = param_tuple->variables[i]->type; - GB_ASSERT(is_type_slice(variadic_type)); - variadic_type = base_type(variadic_type)->Slice.elem; - if (!is_type_any(variadic_type)) { - for (; i < arg_count; i++) { - args[i] = lb_emit_conv(p, args[i], variadic_type); - } - } else { - for (; i < arg_count; i++) { - args[i] = lb_emit_conv(p, args[i], default_type(args[i].type)); - } - } - } else if (variadic) { - isize i = 0; - for (; i < variadic_index; i++) { - Entity *e = param_tuple->variables[i]; - if (e->kind == Entity_Variable) { - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - if (!vari_expand) { - Type *variadic_type = param_tuple->variables[i]->type; - GB_ASSERT(is_type_slice(variadic_type)); - variadic_type = base_type(variadic_type)->Slice.elem; - for (; i < arg_count; i++) { - args[i] = lb_emit_conv(p, args[i], variadic_type); - } - } - } else { - for (isize i = 0; i < param_count; i++) { - Entity *e = param_tuple->variables[i]; - if (e->kind == Entity_Variable) { - if (args[i].value == nullptr) { - continue; - } - GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string)); - if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) { - GB_ASSERT(LLVMIsNull(args[i].value)); - args[i] = lb_typeid(p->module, args[i].type); - } else { - args[i] = lb_emit_conv(p, args[i], e->type); - } - } - } - } - - if (variadic && !vari_expand && !is_c_vararg) { - // variadic call argument generation - Type *slice_type = param_tuple->variables[variadic_index]->type; - Type *elem_type = base_type(slice_type)->Slice.elem; - lbAddr slice = lb_add_local_generated(p, slice_type, true); - isize slice_len = arg_count+1 - (variadic_index+1); - - if (slice_len > 0) { - lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); - - for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) { - lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j); - lb_emit_store(p, addr, args[i]); - } - - lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0); - lbValue len = lb_const_int(m, t_int, slice_len); - lb_fill_slice(p, slice, base_elem, len); - } - - arg_count = param_count; - args[variadic_index] = lb_addr_load(p, slice); - } - } - - if (variadic && variadic_index+1 < param_count) { - for (isize i = variadic_index+1; i < param_count; i++) { - Entity *e = param_tuple->variables[i]; - args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos); - } - } - - isize final_count = param_count; - if (is_c_vararg) { - final_count = arg_count; - } - - if (param_tuple != nullptr) { - for (isize i = 0; i < gb_min(args.count, param_tuple->variables.count); i++) { - Entity *e = param_tuple->variables[i]; - if (args[i].type == nullptr) { - continue; - } else if (is_type_untyped_uninit(args[i].type)) { - args[i] = lb_const_undef(m, e->type); - } else if (is_type_untyped_nil(args[i].type)) { - args[i] = lb_const_nil(m, e->type); - } - } - } - - auto call_args = array_slice(args, 0, final_count); - return lb_emit_call(p, value, call_args, ce->inlining); + GB_ASSERT(ce->split_args != nullptr); + return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args); } -- cgit v1.2.3 From 18746c1444c8137fc0d78659a66c8f63079963e8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 00:40:02 +0100 Subject: Refactor call argument checking to a single procedure --- src/check_expr.cpp | 249 +++++++++++++++++++++-------------------------------- 1 file changed, 97 insertions(+), 152 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5b1f1a73c..b9cc311a8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5994,6 +5994,75 @@ gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice const &positional_operands, Array const &named_operands, + CallArgumentErrorMode show_error_mode, + CallArgumentData *data) { + + bool return_on_failure = show_error_mode == CallArgumentMode_NoErrors; + + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } + + if (e == nullptr) { + GB_ASSERT(proc_type == nullptr); + e = entity_of_node(ident); + proc_type = e->type; + } + + proc_type = base_type(proc_type); + GB_ASSERT(proc_type->kind == Type_Proc); + + CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, show_error_mode, data); + if (return_on_failure && err != CallArgumentError_None) { + return false; + } + + Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e; + if (!return_on_failure) { + add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); + } + } + + if (data->gen_entity != nullptr) { + Entity *e = data->gen_entity; + DeclInfo *decl = data->gen_entity->decl_info; + CheckerContext ctx = *c; + ctx.scope = decl->scope; + ctx.decl = decl; + ctx.proc_name = e->token.string; + ctx.curr_proc_decl = decl; + ctx.curr_proc_sig = e->type; + + GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); + bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !return_on_failure); + if (return_on_failure) { + if (!ok) { + return false; + } + + } else { + decl->where_clauses_evaluated = true; + if (ok && (data->gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { + check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); + } + if (is_type_proc(data->gen_entity->type)) { + Type *t = base_type(entity_to_use->type); + data->result_type = t->Proc.results; + } + } + } + + return true; +} + gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(CheckerContext *c, Operand *operand, Ast *call) { ast_node(ce, CallExpr, call); @@ -6089,11 +6158,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch defer (array_free(&named_operands)); if (procs.count == 1) { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } Entity *e = procs[0]; @@ -6105,46 +6169,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch return data; } - CallArgumentError err = check_call_arguments_internal(c, call, e->type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); - if (err != CallArgumentError_None) { - - } - - - Type *proc_type = base_type(operand->type); - - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - - proc_type = base_type(entity_to_use->type); - } - - if (proc_type && proc_type->kind == Type_Proc) { - data.result_type = proc_type->Proc.results; - add_type_and_value(c, operand->expr, operand->mode, proc_type, operand->value); - } - - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - } - + check_call_arguments_new_and_improved_single(c, call, operand, + e, e->type, + positional_operands, named_operands, + CallArgumentMode_ShowErrors, + &data); return data; } @@ -6256,7 +6285,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch Entity *p = procs[i]; Type *pt = base_type(p->type); if (pt != nullptr && is_type_proc(pt)) { - CallArgumentError err = CallArgumentError_None; CallArgumentData data = {}; CheckerContext ctx = *c; @@ -6264,26 +6292,17 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch ctx.allow_polymorphic_types = is_type_polymorphic(pt); ctx.hide_polymorphic_errors = true; - err = check_call_arguments_internal(&ctx, call, pt, p, positional_operands, named_operands, CallArgumentMode_NoErrors, &data); - if (err != CallArgumentError_None) { + bool is_a_candidate = check_call_arguments_new_and_improved_single(&ctx, call, operand, + p, pt, + positional_operands, named_operands, + CallArgumentMode_NoErrors, + &data); + if (!is_a_candidate) { continue; } isize index = i; if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - if (!evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) { - continue; - } - array_add(&proc_entities, data.gen_entity); index = proc_entities.count-1; } @@ -6449,41 +6468,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch Array named_operands = {}; - Type *proc_type = e->type; - CallArgumentData data = {}; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); - gb_unused(err); - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - proc_type = base_type(entity_to_use->type); - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); - } - - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - } - - if (is_type_proc(proc_type)) { - data.result_type = proc_type->Proc.results; - } - + check_call_arguments_new_and_improved_single(c, call, operand, + e, e->type, + positional_operands, named_operands, + CallArgumentMode_ShowErrors, + &data); return data; } @@ -6539,24 +6528,18 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex return check_call_arguments_new_and_improved_proc_group(c, operand, call); } - auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); auto named_operands = array_make(heap_allocator(), 0, 0); defer (array_free(&positional_operands)); defer (array_free(&named_operands)); - - Slice visited = {}; - if (positional_args.count > 0) { isize lhs_count = -1; bool is_variadic = false; Entity **lhs = nullptr; if (pt != nullptr) { lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); - } else if (operand->mode == Addressing_ProcGroup) { - // TODO } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } @@ -6597,49 +6580,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } if (!any_failure) { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - - Entity *e = entity_of_node(ident); - - TokenPos pos = ast_token(call).pos; - - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); - gb_unused(err); - Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); - } - if (data.gen_entity != nullptr) { - Entity *e = data.gen_entity; - DeclInfo *decl = data.gen_entity->decl_info; - CheckerContext ctx = *c; - ctx.scope = decl->scope; - ctx.decl = decl; - ctx.proc_name = e->token.string; - ctx.curr_proc_decl = decl; - ctx.curr_proc_sig = e->type; - - GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit); - bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true); - decl->where_clauses_evaluated = true; - - if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) { - check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags); - } - - if (is_type_proc(data.gen_entity->type)) { - Type *t = base_type(entity_to_use->type); - // GB_ASSERT_MSG(!is_type_polymorphic(t), "%s", expr_to_string(call)); - data.result_type = t->Proc.results; - - } - } + check_call_arguments_new_and_improved_single(c, call, operand, + nullptr, nullptr, + positional_operands, named_operands, + CallArgumentMode_ShowErrors, + &data); } else if (pt) { data.result_type = pt->results; } @@ -6991,16 +6936,16 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O -// returns true on failure -gb_internal bool check_call_parameter_mixture(Operand *operand, Slice const &args, char const *context, bool allow_mixed=false) { - bool failure = false; +// returns true on success +gb_internal bool check_call_parameter_mixture(Slice const &args, char const *context, bool allow_mixed=false) { + bool success = true; if (args.count > 0) { if (allow_mixed) { bool was_named = false; for (Ast *arg : args) { if (was_named && arg->kind != Ast_FieldValue) { error(arg, "Non-named parameter is not allowed to follow named parameter i.e. 'field = value' in a %s", context); - failure = true; + success = false; break; } was_named = was_named || arg->kind == Ast_FieldValue; @@ -7016,16 +6961,16 @@ gb_internal bool check_call_parameter_mixture(Operand *operand, Slice con } if (mix) { error(arg, "Mixture of 'field = value' and value elements in a %s is not allowed", context); - failure = true; + success = false; } } } } - return failure; + return success; } -#define CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(context_, ...) if (check_call_parameter_mixture(operand, args, context_, ##__VA_ARGS__)) { \ +#define CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN(context_, ...) if (!check_call_parameter_mixture(args, context_, ##__VA_ARGS__)) { \ operand->mode = Addressing_Invalid; \ operand->expr = call; \ return Expr_Stmt; \ -- cgit v1.2.3 From b2ced834ba01c61c8ec842af2de5f480d1e93462 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 00:43:51 +0100 Subject: Minor code reshuffle --- src/check_expr.cpp | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b9cc311a8..8731a0caf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -38,9 +38,9 @@ gb_global char const *CallArgumentError_strings[CallArgumentError_MAX] = { }; -enum CallArgumentErrorMode { - CallArgumentMode_NoErrors, - CallArgumentMode_ShowErrors, +enum struct CallArgumentErrorMode { + NoErrors, + ShowErrors, }; struct CallArgumentData { @@ -5362,7 +5362,11 @@ gb_internal isize lookup_procedure_parameter(Type *type, String const ¶meter return lookup_procedure_parameter(&type->Proc, parameter_name); } -gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) { +gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, Ast *call, + Entity *entity, Type *proc_type, + Array positional_operands, Array const &named_operands, + CallArgumentErrorMode show_error_mode, + CallArgumentData *data) { TEMPORARY_ALLOCATOR_GUARD(); CallArgumentError err = CallArgumentError_None; @@ -5377,7 +5381,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A bool variadic = pt->variadic; bool vari_expand = (ce->ellipsis.pos.line != 0); i64 score = 0; - bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + bool show_error = show_error_mode == CallArgumentErrorMode::ShowErrors; Type *final_proc_type = proc_type; Entity *gen_entity = nullptr; @@ -6000,7 +6004,7 @@ gb_internal bool check_call_arguments_new_and_improved_single(CheckerContext *c, CallArgumentErrorMode show_error_mode, CallArgumentData *data) { - bool return_on_failure = show_error_mode == CallArgumentMode_NoErrors; + bool return_on_failure = show_error_mode == CallArgumentErrorMode::NoErrors; Ast *ident = operand->expr; while (ident->kind == Ast_SelectorExpr) { @@ -6017,7 +6021,7 @@ gb_internal bool check_call_arguments_new_and_improved_single(CheckerContext *c, proc_type = base_type(proc_type); GB_ASSERT(proc_type->kind == Type_Proc); - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, show_error_mode, data); + CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data); if (return_on_failure && err != CallArgumentError_None) { return false; } @@ -6158,22 +6162,18 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch defer (array_free(&named_operands)); if (procs.count == 1) { - - Entity *e = procs[0]; lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); - if (!check_named_arguments(c, e->type, named_args, &named_operands, true)) { - return data; + if (check_named_arguments(c, e->type, named_args, &named_operands, true)) { + check_call_arguments_new_and_improved_single(c, call, operand, + e, e->type, + positional_operands, named_operands, + CallArgumentErrorMode::ShowErrors, + &data); } - - check_call_arguments_new_and_improved_single(c, call, operand, - e, e->type, - positional_operands, named_operands, - CallArgumentMode_ShowErrors, - &data); return data; } @@ -6295,7 +6295,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch bool is_a_candidate = check_call_arguments_new_and_improved_single(&ctx, call, operand, p, pt, positional_operands, named_operands, - CallArgumentMode_NoErrors, + CallArgumentErrorMode::NoErrors, &data); if (!is_a_candidate) { continue; @@ -6471,7 +6471,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch check_call_arguments_new_and_improved_single(c, call, operand, e, e->type, positional_operands, named_operands, - CallArgumentMode_ShowErrors, + CallArgumentErrorMode::ShowErrors, &data); return data; } @@ -6583,7 +6583,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex check_call_arguments_new_and_improved_single(c, call, operand, nullptr, nullptr, positional_operands, named_operands, - CallArgumentMode_ShowErrors, + CallArgumentErrorMode::ShowErrors, &data); } else if (pt) { data.result_type = pt->results; -- cgit v1.2.3 From 15e31e47fa73fdf9d71321c4a3021c37c063cca8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 01:24:57 +0100 Subject: Remove in order requirement for named parameters --- src/check_expr.cpp | 107 ----------------------------------------------------- 1 file changed, 107 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8731a0caf..9d87ffdea 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -117,8 +117,6 @@ gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, Stri gb_internal bool is_diverging_expr(Ast *expr); -gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, bool show_error); - gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_); enum LoadDirectiveResult { @@ -5413,10 +5411,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } }); - if (check_order_of_call_arguments(c, proc_type, call, show_error)) { - return CallArgumentError_OutOfOrderParameters; - } - isize positional_operand_count = positional_operands.count; if (variadic) { positional_operand_count = gb_min(positional_operands.count, pt->variadic_index); @@ -5839,99 +5833,6 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco return true; } -gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, Type *proc_type, Ast *call, bool show_error) { - CallArgumentError err = CallArgumentError_None; - - if (proc_type == nullptr || !is_type_proc(proc_type)) { - // ignore for the time being - return err; - } - - ast_node(ce, CallExpr, call); - if (!is_call_expr_field_value(ce)) { - return err; - } - - TypeProc *pt = &base_type(proc_type)->Proc; - isize param_count = pt->param_count; - - TEMPORARY_ALLOCATOR_GUARD(); - - auto arg_order_indices = slice_make(temporary_allocator(), ce->args.count); - auto visited = slice_make(temporary_allocator(), param_count); - - for_array(i, ce->args) { - Ast *arg = ce->args[i]; - ast_node(fv, FieldValue, arg); - - Ast *field = fv->field; - String name = {}; - if (field != nullptr && field->kind == Ast_Ident) { - name = field->Ident.token.string; - } else { - err = CallArgumentError_InvalidFieldValue; - if (show_error) { - gbString s = expr_to_string(arg); - error(arg, "Invalid parameter name '%s' in procedure call", s); - gb_string_free(s); - } - } - - isize index = lookup_procedure_parameter(pt, name); - if (index < 0) { - err = CallArgumentError_InvalidFieldValue; - if (show_error) { - error(arg, "No parameter named '%.*s' for this procedure type", LIT(name)); - } - } - if (visited[index]) { - err = CallArgumentError_DuplicateParameter; - if (show_error) { - error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name)); - } - } - arg_order_indices[i] = index; - } - - if (err) { - return err; - } - - for (isize i = 0; i < arg_order_indices.count-1; i++) { - isize a = arg_order_indices[i+0]; - isize b = arg_order_indices[i+1]; - GB_ASSERT(a != b); - if (a > b) { - err = CallArgumentError_OutOfOrderParameters; - if (show_error) { - Ast *arg_a = ce->args[i+0]; - Ast *arg_b = ce->args[i+1]; - - isize curr_a_order = a; - for (isize j = i; j >= 0; j--) { - isize j_order = arg_order_indices[j]; - if (b < j_order && j_order < curr_a_order) { - curr_a_order = j_order; - arg_a = ce->args[j]; - } - } - - - ast_node(fv_a, FieldValue, arg_a); - ast_node(fv_b, FieldValue, arg_b); - - gbString s_a = expr_to_string(fv_a->field); - gbString s_b = expr_to_string(fv_b->field); - error(arg_b, "Parameter names out of order, expected '%s' to be called before '%s'", s_b, s_a); - gb_string_free(s_b); - gb_string_free(s_a); - } - } - } - - return err; -} - gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice const &named_args, Array *named_operands, bool show_error) { bool success = true; @@ -5974,12 +5875,6 @@ gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Sliceparams->Tuple.variables[param_index]; if (!is_type_polymorphic(e->type)) { type_hint = e->type; @@ -6498,8 +6393,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex bool any_failure = false; - // bool vari_expand = (ce->ellipsis.pos.line != 0); - // Split positional and named args into separate arrays/slices Slice positional_args = {}; Slice named_args = {}; -- cgit v1.2.3 From 8a890fd3d3cc1d11417d1da37bced9ba5715e612 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 01:32:35 +0100 Subject: Remove `new_and_improved` in the name --- src/check_expr.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9d87ffdea..99017f434 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5893,7 +5893,7 @@ gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice const &positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, @@ -5963,7 +5963,7 @@ gb_internal bool check_call_arguments_new_and_improved_single(CheckerContext *c, } -gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(CheckerContext *c, Operand *operand, Ast *call) { +gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, Operand *operand, Ast *call) { ast_node(ce, CallExpr, call); GB_ASSERT(ce->split_args != nullptr); @@ -6063,7 +6063,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); if (check_named_arguments(c, e->type, named_args, &named_operands, true)) { - check_call_arguments_new_and_improved_single(c, call, operand, + check_call_arguments_single(c, call, operand, e, e->type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, @@ -6187,7 +6187,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch ctx.allow_polymorphic_types = is_type_polymorphic(pt); ctx.hide_polymorphic_errors = true; - bool is_a_candidate = check_call_arguments_new_and_improved_single(&ctx, call, operand, + bool is_a_candidate = check_call_arguments_single(&ctx, call, operand, p, pt, positional_operands, named_operands, CallArgumentErrorMode::NoErrors, @@ -6363,7 +6363,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch Array named_operands = {}; - check_call_arguments_new_and_improved_single(c, call, operand, + check_call_arguments_single(c, call, operand, e, e->type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, @@ -6375,7 +6375,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(Ch } -gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContext *c, Operand *operand, Ast *call) { +gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Ast *call) { Type *proc_type = nullptr; CallArgumentData data = {}; @@ -6418,7 +6418,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } if (operand->mode == Addressing_ProcGroup) { - return check_call_arguments_new_and_improved_proc_group(c, operand, call); + return check_call_arguments_proc_group(c, operand, call); } auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); @@ -6473,7 +6473,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } if (!any_failure) { - check_call_arguments_new_and_improved_single(c, call, operand, + check_call_arguments_single(c, call, operand, nullptr, nullptr, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, @@ -7045,7 +7045,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } - CallArgumentData data = check_call_arguments_new_and_improved(c, operand, call); + CallArgumentData data = check_call_arguments(c, operand, call); Type *result_type = data.result_type; gb_zero_item(operand); operand->expr = call; -- cgit v1.2.3 From c48057081e451c81524c7727ec3ccf434a45726f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 14:39:23 +0100 Subject: Fix nullptr entity case --- src/check_expr.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 99017f434..83e44b39f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5908,11 +5908,13 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera } if (e == nullptr) { - GB_ASSERT(proc_type == nullptr); e = entity_of_node(ident); - proc_type = e->type; + if (e != nullptr) { + proc_type = e->type; + } } + GB_ASSERT(proc_type != nullptr); proc_type = base_type(proc_type); GB_ASSERT(proc_type->kind == Type_Proc); @@ -5922,12 +5924,10 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera } Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e; - if (!return_on_failure) { + if (!return_on_failure && entity_to_use != nullptr) { add_entity_use(c, ident, entity_to_use); - if (entity_to_use != nullptr) { - update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); - add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); - } + update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); + add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } if (data->gen_entity != nullptr) { @@ -6474,7 +6474,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (!any_failure) { check_call_arguments_single(c, call, operand, - nullptr, nullptr, + nullptr, proc_type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, &data); -- cgit v1.2.3