From 575c7ff031f67ec4c479fa1cd6e22491e2b7a79e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Feb 2021 15:09:32 +0000 Subject: [PATCH] Patch issue with minimum dependency system and how it interacts with para poly procedures --- src/check_expr.cpp | 69 +++++++++++++++++++++++++++++++++++++------- src/check_type.cpp | 19 ++++++++++++ src/checker.cpp | 49 ++++++++++++++++++++++++++++--- src/entity.cpp | 2 ++ src/llvm_backend.cpp | 7 +++-- 5 files changed, 129 insertions(+), 17 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 656ac8838..23db2197a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -14,7 +14,27 @@ enum CallArgumentError { CallArgumentError_ParameterMissing, CallArgumentError_DuplicateParameter, CallArgumentError_NoneConstantParameter, + + CallArgumentError_MAX, }; +char const *CallArgumentError_strings[CallArgumentError_MAX] = { + "None", + "NoneProcedureType", + "WrongTypes", + "NonVariadicExpand", + "VariadicTuple", + "MultipleVariadicExpand", + "AmbiguousPolymorphicVariadic", + "ArgumentCount", + "TooFewArguments", + "TooManyArguments", + "InvalidFieldValue", + "ParameterNotFound", + "ParameterMissing", + "DuplicateParameter", + "NoneConstantParameter", +}; + enum CallArgumentErrorMode { CallArgumentMode_NoErrors, @@ -25,6 +45,7 @@ struct CallArgumentData { Entity *gen_entity; i64 score; Type * result_type; + Type * proc_type; }; struct PolyProcData { @@ -243,7 +264,6 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *c, Entity *base_enti } - gbAllocator a = heap_allocator(); Array operands = {}; @@ -344,7 +364,6 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *c, Entity *base_enti } - Ast *proc_lit = clone_ast(old_decl->proc_lit); ast_node(pl, ProcLit, proc_lit); // NOTE(bill): Associate the scope declared above withinth this procedure declaration's type @@ -6993,8 +7012,14 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, e->type, e, 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) { + add_entity_use(c, ident, entity_to_use); + data.proc_type = entity_to_use->type; + } return data; } @@ -7070,6 +7095,13 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type auto valids = array_make(heap_allocator(), 0, procs.count); defer (array_free(&valids)); + auto proc_entities = array_make(heap_allocator(), 0, procs.count*2); + defer (array_free(&proc_entities)); + for_array(i, procs) { + array_add(&proc_entities, procs[i]); + } + + gbString expr_name = expr_to_string(operand->expr); defer (gb_string_free(expr_name)); @@ -7086,10 +7118,10 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ctx.hide_polymorphic_errors = true; err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data); - if (err != CallArgumentError_None) { continue; } + isize index = i; if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; @@ -7104,10 +7136,13 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type 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 = i; + item.index = index; item.score = data.score; array_add(&valids, item); } @@ -7116,13 +7151,13 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type 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 = procs[valids[0].index]; + Entity *best_entity = proc_entities[valids[0].index]; for (isize i = 1; i < valids.count; i++) { if (best_score > valids[i].score) { valids.count = i; break; } - if (best_entity == procs[valids[i].index]) { + if (best_entity == proc_entities[valids[i].index]) { valids.count = i; break; } @@ -7200,7 +7235,7 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type error_line(")\n"); for (isize i = 0; i < valids.count; i++) { - Entity *proc = procs[valids[i].index]; + Entity *proc = proc_entities[valids[i].index]; TokenPos pos = proc->token.pos; Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc); gbString pt = nullptr; @@ -7248,13 +7283,16 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type ident = s; } - Entity *e = procs[valids[0].index]; + Entity *e = proc_entities[valids[0].index]; proc_type = e->type; CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + add_entity_use(c, ident, entity_to_use); + data.proc_type = entity_to_use->type; + } if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; @@ -7285,7 +7323,10 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type CallArgumentData data = {}; CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data); Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e; - add_entity_use(c, ident, entity_to_use); + if (entity_to_use != nullptr) { + add_entity_use(c, ident, entity_to_use); + data.proc_type = entity_to_use->type; + } if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; @@ -7789,6 +7830,10 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr } Type *pt = base_type(proc_type); + if (data.proc_type != nullptr) { + pt = base_type(data.proc_type); + } + if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) { if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) { @@ -7852,6 +7897,8 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr operand->mode = Addressing_OptionalOk; } + add_type_and_value(c->info, operand->expr, operand->mode, operand->type, operand->value); + return Expr_Expr; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 6377f4e6e..604dfd420 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1674,6 +1674,25 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is } } } + 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; + } + } + if (!ok) { + if (false) { + 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); + } + success = false; + } + } + 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); diff --git a/src/checker.cpp b/src/checker.cpp index cc2d28dc8..bf3469fde 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -646,6 +646,7 @@ void add_package_dependency(CheckerContext *c, char const *package_name, char co 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); + e->flags |= EntityFlag_Used; GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); ptr_set_add(&c->decl->deps, e); @@ -1721,6 +1722,13 @@ void add_dependency_to_set(Checker *c, Entity *entity) { } } +void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { + Entity *e = scope_lookup(scope, name); + e->flags |= EntityFlag_Used; + add_dependency_to_set(c, e); +} + + void generate_minimum_dependency_set(Checker *c, Entity *start) { isize entity_count = c->info.entities.count; @@ -1775,7 +1783,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("bswap_f64"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { - add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); + force_add_dependency_entity(c, c->info.runtime_package->scope, required_runtime_entities[i]); } if (build_context.no_crt) { @@ -1787,7 +1795,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("_fltused"), }; for (isize i = 0; i < gb_count_of(required_no_crt_entities); i++) { - add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_no_crt_entities[i])); + force_add_dependency_entity(c, c->info.runtime_package->scope, required_no_crt_entities[i]); } } @@ -1796,7 +1804,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("heap_allocator"), }; for (isize i = 0; i < gb_count_of(required_os_entities); i++) { - add_dependency_to_set(c, scope_lookup(os->scope, required_os_entities[i])); + force_add_dependency_entity(c, os->scope, required_os_entities[i]); } @@ -1808,7 +1816,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("dynamic_array_expr_error"), }; for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { - add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, bounds_check_entities[i])); + force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]); } } @@ -1896,6 +1904,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { } } } else { + start->flags |= EntityFlag_Used; add_dependency_to_set(c, start); } } @@ -4358,6 +4367,9 @@ void check_proc_info(Checker *c, ProcInfo pi) { } check_proc_body(&ctx, pi.token, pi.decl, pi.type, pi.body); + if (pi.body != nullptr && pi.decl->entity != nullptr) { + pi.decl->entity->flags |= EntityFlag_ProcBodyChecked; + } } GB_THREAD_PROC(check_proc_info_worker_proc) { @@ -4368,6 +4380,33 @@ GB_THREAD_PROC(check_proc_info_worker_proc) { return 0; } +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 + // NOTE(2021-02-26, bill): Actually fix this race condition + for_array(i, c->info.minimum_dependency_set.entries) { + Entity *e = c->info.minimum_dependency_set.entries[i].ptr; + if (e != nullptr && e->kind == Entity_Procedure) { + if (!e->Procedure.is_foreign && (e->flags & EntityFlag_ProcBodyChecked) == 0) { + GB_ASSERT(e->decl_info != nullptr); + + ProcInfo pi = {}; + pi.file = e->file; + pi.token = e->token; + pi.decl = e->decl_info; + pi.type = e->type; + + Ast *pl = e->decl_info->proc_lit; + GB_ASSERT(pl != nullptr); + pi.body = pl->ProcLit.body; + pi.tags = pl->ProcLit.tags; + + check_proc_info(c, pi); + } + } + } +} void check_parsed_files(Checker *c) { #define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) @@ -4447,6 +4486,8 @@ void check_parsed_files(Checker *c) { // Calculate initialization order of global variables calculate_global_init_order(c); + TIME_SECTION("check bodies have all been checked"); + check_unchecked_bodies(c); TIME_SECTION("add untyped expression values"); // Add untyped expression values diff --git a/src/entity.cpp b/src/entity.cpp index 1712c7f98..7951cf614 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -57,6 +57,8 @@ enum EntityFlag : u32 { EntityFlag_SoaPtrField = 1<<19, // to allow s.x[0] where `s.x` is a pointer rather than a slice + EntityFlag_ProcBodyChecked = 1<<20, + EntityFlag_CVarArg = 1<<21, EntityFlag_AutoCast = 1<<22, diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 94c9097cc..97e88cb2b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -370,6 +370,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { if (p->module != e->code_gen_module) { gb_mutex_lock(&p->module->mutex); } + GB_ASSERT(e->code_gen_module != nullptr); found = map_get(&e->code_gen_module->values, hash_entity(e)); if (p->module != e->code_gen_module) { gb_mutex_unlock(&p->module->mutex); @@ -7109,6 +7110,7 @@ lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array if (p->module != e->code_gen_module) { gb_mutex_lock(&p->module->mutex); } + GB_ASSERT(e->code_gen_module != nullptr); found = map_get(&e->code_gen_module->values, hash_entity(e)); if (p->module != e->code_gen_module) { gb_mutex_unlock(&p->module->mutex); @@ -8564,6 +8566,7 @@ LLVMValueRef lb_lookup_runtime_procedure(lbModule *m, String const &name) { if (m != e->code_gen_module) { gb_mutex_lock(&m->mutex); } + GB_ASSERT(e->code_gen_module != nullptr); found = map_get(&e->code_gen_module->values, hash_entity(e)); if (m != e->code_gen_module) { gb_mutex_unlock(&m->mutex); @@ -9554,9 +9557,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { expr = unparen_expr(expr); + TokenPos expr_pos = ast_token(expr).pos; TypeAndValue tv = type_and_value_of_expr(expr); - GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "%s", expr_to_string(expr)); - GB_ASSERT(tv.mode != Addressing_Type); + GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %.*s(%td:%td)\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), LIT(expr_pos.file), expr_pos.line, expr_pos.column, LIT(p->name), type_to_string(p->type)); if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Short on constant values