From afb5538e832d7772b5149c899e78ccb8edf2dde3 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 1 Oct 2017 20:27:02 +0100 Subject: [PATCH] Default procedure values for `proc` --- src/check_expr.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++-- src/ir.cpp | 16 ++++++++++ src/types.cpp | 3 +- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index afa8327a0..ceac342b4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1071,7 +1071,26 @@ Array check_struct_fields(Checker *c, AstNode *node, Array if (is_operand_nil(o)) { default_is_nil = true; } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); + if (default_value->kind == AstNode_ProcLit) { + value = exact_value_procedure(default_value); + } else { + Entity *e = nullptr; + if (o.mode == Addressing_Value && is_type_proc(o.type)) { + Operand x = {}; + if (default_value->kind == AstNode_Ident) { + e = check_ident(c, &x, default_value, nullptr, nullptr, false); + } else if (default_value->kind == AstNode_SelectorExpr) { + e = check_selector(c, &x, default_value, nullptr); + } + } + + if (e != nullptr && e->kind == Entity_Procedure) { + value = exact_value_procedure(e->identifier); + add_entity_use(c, e->identifier, e); + } else { + error(default_value, "Default parameter must be a constant"); + } + } } else { value = o.value; } @@ -2132,7 +2151,26 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (is_operand_nil(o)) { default_is_nil = true; } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); + if (default_value->kind == AstNode_ProcLit) { + value = exact_value_procedure(default_value); + } else { + Entity *e = nullptr; + if (o.mode == Addressing_Value && is_type_proc(o.type)) { + Operand x = {}; + if (default_value->kind == AstNode_Ident) { + e = check_ident(c, &x, default_value, nullptr, nullptr, false); + } else if (default_value->kind == AstNode_SelectorExpr) { + e = check_selector(c, &x, default_value, nullptr); + } + } + + if (e != nullptr && e->kind == Entity_Procedure) { + value = exact_value_procedure(e->identifier); + add_entity_use(c, e->identifier, e); + } else { + error(default_value, "Default parameter must be a constant"); + } + } } else { value = o.value; } @@ -2201,7 +2239,26 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (is_operand_nil(o)) { default_is_nil = true; } else if (o.mode != Addressing_Constant) { - error(default_value, "Default parameter must be a constant"); + if (default_value->kind == AstNode_ProcLit) { + value = exact_value_procedure(default_value); + } else { + Entity *e = nullptr; + if (o.mode == Addressing_Value && is_type_proc(o.type)) { + Operand x = {}; + if (default_value->kind == AstNode_Ident) { + e = check_ident(c, &x, default_value, nullptr, nullptr, false); + } else if (default_value->kind == AstNode_SelectorExpr) { + e = check_selector(c, &x, default_value, nullptr); + } + } + + if (e != nullptr && e->kind == Entity_Procedure) { + value = exact_value_procedure(e->identifier); + add_entity_use(c, e->identifier, e); + } else { + error(default_value, "Default parameter must be a constant"); + } + } } else { value = o.value; } @@ -2682,11 +2739,22 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array Type *params = check_get_params(c, c->context.scope, pt->params, &variadic, &success, &specialization_count, operands); Type *results = check_get_results(c, c->context.scope, pt->results); + isize param_count = 0; isize result_count = 0; if (params) param_count = params ->Tuple.variables.count; if (results) result_count = results->Tuple.variables.count; + if (param_count > 0) { + for_array(i, params->Tuple.variables) { + Entity *param = params->Tuple.variables[i]; + if (param->kind == Entity_Variable && param->Variable.default_value.kind == ExactValue_Procedure) { + type->Proc.has_proc_default_values = true; + break; + } + } + } + type->Proc.node = proc_type_node; type->Proc.scope = c->context.scope; type->Proc.params = params; diff --git a/src/ir.cpp b/src/ir.cpp index 9a18f9195..2c874584f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7422,6 +7422,22 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->module->stmt_state_flags = prev_stmt_state_flags; } + + + if (proc->type->Proc.has_proc_default_values) { + auto *p = &proc->type->Proc; + for_array(i, p->params->Tuple.variables) { + Entity *f = p->params->Tuple.variables[i]; + if (f->kind == Entity_Variable && f->Variable.default_value.kind == ExactValue_Procedure) { + AstNode *expr = f->Variable.default_value.value_procedure; + GB_ASSERT(expr != nullptr); + if (expr->kind == AstNode_ProcLit) { + ir_gen_anonymous_proc_lit(proc->module, proc->name, expr, proc); + } + } + } + } + } diff --git a/src/types.cpp b/src/types.cpp index 7cc85f40d..dac5ff8de 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -139,14 +139,15 @@ struct TypeStruct { Type * results; /* Type_Tuple */ \ i32 param_count; \ i32 result_count; \ - bool return_by_pointer; \ Type ** abi_compat_params; \ Type * abi_compat_result_type; \ + bool return_by_pointer; \ bool variadic; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ bool is_poly_specialized; \ + bool has_proc_default_values; \ isize specialization_count; \ ProcCallingConvention calling_convention; \ }) \