diff --git a/src/check_decl.cpp b/src/check_decl.cpp index da2214d89..1a6fad918 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -338,7 +338,7 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, if (type_expr) { Type *t = check_type(ctx, type_expr); - if (!is_type_constant_type(t)) { + if (!is_type_constant_type(t) && !is_type_proc(t)) { gbString str = type_to_string(t); error(type_expr, "Invalid constant type '%s'", str); gb_string_free(str); @@ -392,6 +392,25 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, } if (entity != nullptr) { + if (e->type != nullptr) { + Operand x = {}; + x.type = entity->type; + x.mode = Addressing_Variable; + if (!check_is_assignable_to(ctx, &x, e->type)) { + gbString expr_str = expr_to_string(init); + gbString op_type_str = type_to_string(entity->type); + gbString type_str = type_to_string(e->type); + error(e->token, + "Cannot assign '%s' of type '%s' to '%s'", + expr_str, + op_type_str, + type_str); + + gb_string_free(type_str); + gb_string_free(op_type_str); + gb_string_free(expr_str); + } + } // NOTE(bill): Override aliased entity switch (entity->kind) { @@ -583,11 +602,45 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { check_open_scope(ctx, pl->type); defer (check_close_scope(ctx)); + Type *decl_type = nullptr; + + if (d->type_expr != nullptr) { + decl_type = check_type(ctx, d->type_expr); + if (!is_type_proc(decl_type)) { + gbString str = type_to_string(decl_type); + error(d->type_expr, "Expected a procedure type, got '%s'", str); + gb_string_free(str); + } + } + auto tmp_ctx = *ctx; tmp_ctx.allow_polymorphic_types = true; + if (decl_type != nullptr) { + tmp_ctx.type_hint = decl_type; + } check_procedure_type(&tmp_ctx, proc_type, pl->type); + if (decl_type != nullptr) { + Operand x = {}; + x.type = e->type; + x.mode = Addressing_Variable; + if (!check_is_assignable_to(ctx, &x, decl_type)) { + gbString expr_str = expr_to_string(d->proc_lit); + gbString op_type_str = type_to_string(e->type); + gbString type_str = type_to_string(decl_type); + error(e->token, + "Cannot assign '%s' of type '%s' to '%s'", + expr_str, + op_type_str, + type_str); + + gb_string_free(type_str); + gb_string_free(op_type_str); + gb_string_free(expr_str); + } + } + TypeProc *pt = &proc_type->Proc; AttributeContext ac = make_attribute_context(e->Procedure.link_prefix); diff --git a/src/checker.cpp b/src/checker.cpp index 4712876de..9abd8c499 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2591,7 +2591,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { pl->type->ProcType.calling_convention = cc; } d->proc_lit = init; - d->type_expr = pl->type; + d->type_expr = vd->type; } else if (init->kind == Ast_ProcGroup) { ast_node(pg, ProcGroup, init); e = alloc_entity_proc_group(d->scope, token, nullptr); @@ -2599,6 +2599,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { error(name, "Procedure groups are not allowed within a foreign block"); } d->init_expr = init; + d->type_expr = vd->type; } else { e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value); d->type_expr = vd->type;