diff options
Diffstat (limited to 'src/check_decl.cpp')
| -rw-r--r-- | src/check_decl.cpp | 224 |
1 files changed, 122 insertions, 102 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 0e41dbbb5..b651e33e6 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) { @@ -10,7 +10,6 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri gbString expr_str = expr_to_string(operand->expr); // TODO(bill): is this a good enough error message? - // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use error(operand->expr, "Cannot assign built-in procedure '%s' in %.*s", expr_str, @@ -44,14 +43,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri } if (operand->mode == Addressing_Type) { - if (e->type != nullptr && is_type_typeid(e->type)) { + if (e->type != nullptr && is_type_typeid(e->type) && !is_type_polymorphic(operand->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 { + ERROR_BLOCK(); + gbString t = type_to_string(operand->type); defer (gb_string_free(t)); - error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); + if (is_type_polymorphic(operand->type)) { + error(operand->expr, "Cannot assign a non-specialized polymorphic type '%s' to variable '%.*s'", t, LIT(e->token.string)); + } else { + error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); + } if (e->type == nullptr) { error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a default type\n", LIT(e->token.string)); } @@ -60,20 +65,17 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri } } - - if (e->type == nullptr) { // 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; } @@ -110,7 +112,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<Ast *> const &inits, String context_name) { +gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) { if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) { return; } @@ -118,17 +120,11 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl // 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<Operand>(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; - for_array(i, operands) { - if (operands[i].mode == Addressing_Invalid) { - // TODO(bill): Should I ignore invalid parameters? - // rhs_count--; - } - } - isize max = gb_min(lhs_count, rhs_count); for (isize i = 0; i < max; i++) { Entity *e = lhs[i]; @@ -138,13 +134,21 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl 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 a return value from 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); } } -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 +188,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 +221,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,17 +236,7 @@ Ast *remove_type_alias_clutter(Ast *node) { } } -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; -} - -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 +282,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); @@ -372,8 +366,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) Type *t = base_type(e->type); if (t->kind == Type_Enum) { - for_array(i, t->Enum.fields) { - Entity *f = t->Enum.fields[i]; + for (Entity *f : t->Enum.fields) { if (f->kind != Entity_Constant) { continue; } @@ -390,7 +383,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; @@ -400,8 +393,8 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { 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 @@ -433,7 +426,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); @@ -596,7 +589,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, 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); } @@ -609,12 +602,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 +616,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 +667,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 +697,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 +740,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 +757,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 @@ -834,9 +827,14 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (ac.test) { e->flags |= EntityFlag_Test; } - if (ac.init) { + if (ac.init && ac.fini) { + error(e->token, "A procedure cannot be both declared as @(init) and @(fini)"); + } else if (ac.init) { e->flags |= EntityFlag_Init; + } else if (ac.fini) { + e->flags |= EntityFlag_Fini; } + if (ac.set_cold) { e->flags |= EntityFlag_Cold; } @@ -952,6 +950,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (ac.require_declaration) { e->flags |= EntityFlag_Require; + pl->inlining = ProcInlining_no_inline; } @@ -1004,7 +1003,7 @@ 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) { @@ -1028,7 +1027,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (ac.deferred_procedure.entity != nullptr) { e->Procedure.deferred_procedure = ac.deferred_procedure; - mpmc_enqueue(&ctx->checker->procs_with_deferred_to_check, e); + mpsc_enqueue(&ctx->checker->procs_with_deferred_to_check, e); } if (is_foreign) { @@ -1121,7 +1120,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); @@ -1142,7 +1141,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, if (ac.require_declaration) { e->flags |= EntityFlag_Require; - mpmc_enqueue(&ctx->info->required_global_variable_queue, e); + mpsc_enqueue(&ctx->info->required_global_variable_queue, e); } @@ -1156,9 +1155,12 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { e->Variable.thread_local_model.len = 0; - // NOTE(bill): ignore this message for the time begin + // NOTE(bill): ignore this message for the time being // error(e->token, "@(thread_local) is not supported for this target platform"); } + if(build_context.no_thread_local) { + e->Variable.thread_local_model.len = 0; + } String context_name = str_lit("variable declaration"); @@ -1239,7 +1241,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; @@ -1253,10 +1255,9 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) pg_entity->type = t_invalid; PtrSet<Entity *> 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]; + for (Ast *arg : pg->args) { Entity *e = nullptr; Operand o = {}; if (arg->kind == Ast_Ident) { @@ -1289,7 +1290,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) ptr_set_destroy(&entity_set); - for_array(j, pge->entities) { + for (isize j = 0; j < pge->entities.count; j++) { Entity *p = pge->entities[j]; if (p->type == t_invalid) { // NOTE(bill): This invalid overload has already been handled @@ -1367,7 +1368,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; } @@ -1431,15 +1432,46 @@ 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; }; -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); @@ -1480,8 +1512,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty { if (type->Proc.param_count > 0) { TypeTuple *params = &type->Proc.params->Tuple; - for_array(i, params->variables) { - Entity *e = params->variables[i]; + for (Entity *e : params->variables) { if (e->kind != Entity_Variable) { continue; } @@ -1489,7 +1520,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty continue; } if (is_blank_ident(e->token)) { - error(e->token, "'using' a procedure parameter requires a non blank identifier"); + error(e->token, "'using' a procedure parameter requires a non blank identifier"); break; } @@ -1499,8 +1530,9 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty if (t->kind == Type_Struct) { Scope *scope = t->Struct.scope; GB_ASSERT(scope != nullptr); - MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) { - Entity *f = scope->elements.entries[i].value; + 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); if (is_value) uvar->flags |= EntityFlag_Value; @@ -1509,6 +1541,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty 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; @@ -1517,45 +1550,50 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty } } - 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); + 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); 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)); 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); 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); { - for_array(i, using_entities) { - Entity *uvar = using_entities[i].uvar; + for (auto const &entry : using_entities) { + Entity *uvar = entry.uvar; Entity *prev = scope_insert(ctx->scope, uvar); gb_unused(prev); // 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); decl->defer_use_checked = true; - for_array(i, bs->stmts) { - Ast *stmt = bs->stmts[i]; + for (Ast *stmt : bs->stmts) { if (stmt->kind == Ast_ValueDecl) { ast_node(vd, ValueDecl, stmt); - for_array(j, vd->names) { - Ast *name = vd->names[j]; + for (Ast *name : vd->names) { if (!is_blank_ident(name)) { if (name->kind == Ast_Ident) { GB_ASSERT(name->Ident.entity != nullptr); @@ -1590,25 +1628,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty check_scope_usage(ctx->checker, ctx->scope); - 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); + add_deps_from_child_to_parent(decl); - // NOTE(bill): Add the dependencies from the procedure literal (lambda) - // But only at the procedure level - for_array(i, decl->deps.entries) { - Entity *e = decl->deps.entries[i].ptr; - ptr_set_add(&decl->parent->deps, e); - } - for_array(i, decl->type_info_deps.entries) { - Type *t = decl->type_info_deps.entries[i].ptr; - ptr_set_add(&decl->parent->type_info_deps, t); - } - - mutex_unlock(&ctx->info->deps_mutex); - } - } + return true; } |