Merge pull request #7208 from Taylbr/poly-proc-fix

Fix: Polymorphic procedures resolving to nil + further fixes
This commit is contained in:
gingerBill
2026-08-05 16:56:34 +02:00
committed by GitHub
8 changed files with 115 additions and 16 deletions

View File

@@ -410,6 +410,15 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
}
if (!src->Proc.is_polymorphic || src->Proc.is_poly_specialized) {
// NOTE: polymorphic procedure check not idempotent without this
if (src->Proc.is_poly_specialized && base_entity->Procedure.generated_from_polymorphic) {
if (are_types_identical(src, dst)) {
if (poly_proc_data) {
poly_proc_data->gen_entity = base_entity;
}
return true;
}
}
return false;
}
@@ -457,9 +466,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
scope->flags |= ScopeFlag_Proc;
nctx.scope = scope;
nctx.allow_polymorphic_types = true;
if (nctx.polymorphic_scope == nullptr) {
nctx.polymorphic_scope = scope;
}
nctx.polymorphic_scope = scope;
auto *pt = &src->Proc;
@@ -1023,17 +1030,6 @@ gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *o
return false;
}
// Handle polymorphic procedure used as default parameter
if (operand->mode == Addressing_Value && is_type_proc(type) && is_type_proc(operand->type)) {
Entity *e = entity_from_expr(operand->expr);
if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type) && !is_type_polymorphic(type)) {
// Special case: Allow a polymorphic procedure to be used as default value for concrete proc type
// during the initial check. It will be properly instantiated when actually used.
if (score_) *score_ = assign_score_function(1);
return true;
}
}
i64 score = check_distance_between_types(c, operand, type, allow_array_programming);
if (score >= 0) {
if (score_) *score_ = assign_score_function(score, is_variadic);

View File

@@ -1791,6 +1791,7 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_
if (e->kind == Entity_Procedure) {
param_value.kind = ParameterValue_Constant;
param_value.value = exact_value_procedure(e->identifier);
param_value.proc_entity = e;
add_entity_use(ctx, e->identifier, e);
} else {
if (e->flags & EntityFlag_Param) {
@@ -2143,8 +2144,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
// 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;
// NOTE(taylbr): Can still have valid type with null expr. Needed for resolving
if (op.mode == Addressing_Invalid || op.type == nullptr) {
op.mode = Addressing_Invalid;
op.type = t_invalid;
}
}
if (is_type_polymorphic_type) {
type = determine_type_from_polymorphic(ctx, type, op);

View File

@@ -111,6 +111,7 @@ enum ParameterValueKind {
struct ParameterValue {
ParameterValueKind kind;
Ast *original_ast_expr;
Entity *proc_entity;
union {
ExactValue value;
Ast *ast_value;

View File

@@ -4785,6 +4785,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TypeProc *procedure_type, Ast* call_expression) {
switch (param_value.kind) {
case ParameterValue_Constant:
if (param_value.proc_entity != nullptr && is_type_proc(parameter_type)) {
lbValue v = lb_find_procedure_value_from_entity(p->module, param_value.proc_entity);
if (v.value != nullptr) {
return lb_emit_conv(p, v, parameter_type);
}
}
if (is_type_constant_type(parameter_type)) {
auto res = lb_const_value(p->module, parameter_type, param_value.value);
return res;