function values as comptime params

This commit is contained in:
2026-07-18 01:35:39 +02:00
parent 9f433af724
commit 85693e57e1
7 changed files with 254 additions and 12 deletions
+57 -1
View File
@@ -623,6 +623,14 @@ ct_coerce_value :: proc(state: ^Ct_State, id: Ct_Value_Id, expected: types.Type,
value.type = expected
return ct_add_value(state, value), true
}
if value.kind == .Function {
_, _, actual_function, actual_ok := types.function_pointer(value.type, store)
_, _, expected_function, expected_ok := types.function_pointer(expected, store)
if actual_ok && expected_ok && types.equal(actual_function, expected_function) {
value.type = expected
return ct_add_value(state, value), true
}
}
if value.kind == .Array {
expected_item, expected_ok := types.node(store, expected)
value_item, value_ok := types.node(store, value.type)
@@ -1040,6 +1048,11 @@ ct_eval_expr :: proc(
}
return ct_add_value(state, Ct_Value{kind=.String, type=value.type, index=string_id}), ct_flow(.Normal), true
}
if value.kind == .Static && value.static_value != INVALID_CT_VALUE &&
int(value.static_value) < len(checker.static_state.values) {
id := ct_clone_graph(state, &checker.static_state, value.static_value)
return ct_observe_value(state, id, expr.span)
}
return ct_add_value(state, Ct_Value{kind=.Type, type=types.INVALID, index=u64(value.type)}), ct_flow(.Normal), true
}
} else if find_import(checker, state.file, expr.qualifier) == ast.INVALID_IMPORT {
@@ -1084,6 +1097,22 @@ ct_eval_expr :: proc(
}
global_expected := type_from_syntax(checker, g.type, g.pkg, g.file)
return ct_eval_expr(state, g.expr, global_expected, depth+1)
case .Function_Literal:
template := ast.Function_Id(u32(expr.integer))
pointer_type, _, ok := function_pointer_type_for_template(
checker,
template,
state.demanded,
state.demanded != nil,
)
if !ok {
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(
state, .Not_Comptime, expr.span, "function literal is not comptime-callable as a value",
)
}
return ct_add_value(state, Ct_Value{
kind=.Function, type=pointer_type, index=u64(template),
}), ct_flow(.Normal), true
case .Comptime:
if expr.left != ast.INVALID_EXPR {
return ct_eval_expr(state, expr.left, expected, depth+1)
@@ -2586,6 +2615,20 @@ ct_eval_call_expr :: proc(state: ^Ct_State, expr: ast.Expr, expected: types.Type
}
return INVALID_CT_VALUE, ct_flow(.Normal), ct_failf(state, .Not_Comptime, expr.span, "unknown intrinsic '%s!'", symbol_text(checker, expr.name))
}
if symbol.is_valid(expr.qualifier) && find_import(checker, state.file, expr.qualifier) == ast.INVALID_IMPORT {
if index, ok := ct_find_binding_index(state, expr.qualifier); ok {
base := ct_binding_value(state, index)
callee, flow, field_ok := ct_eval_field_value(state, base, expr.name, expr.span)
if !field_ok || flow.kind != .Normal {
return INVALID_CT_VALUE, flow, field_ok
}
if callee != INVALID_CT_VALUE && int(callee) < len(state.values) && state.values[callee].kind == .Function {
return ct_eval_template_call(
state, ast.Function_Id(u32(state.values[callee].index)), expr.args, expr.span, expected, depth+1,
)
}
}
}
target_pkg, available := expr_package(checker, expr, state.pkg, state.file, false)
if !available {
return INVALID_CT_VALUE, ct_flow(.Normal), ct_fail(state, .Not_Comptime, expr.span, "unavailable function package")
@@ -2697,6 +2740,13 @@ ct_eval_template_call :: proc(
state.result = previous_result
}
param_start := len(state.bindings)
for comptime_value in comptime_values {
if comptime_value.kind == .Static && comptime_value.static_value != INVALID_CT_VALUE &&
int(comptime_value.static_value) < len(checker.static_state.values) {
value := ct_clone_graph(state, &checker.static_state, comptime_value.static_value)
ct_bind_value(state, comptime_value.name, comptime_value.type, value, false)
}
}
for value, index in runtime_values {
ct_bind_value(state, runtime_names[index], runtime_types[index], value, false)
}
@@ -2884,6 +2934,12 @@ ct_write_comptime_key :: proc(state: ^Ct_State, id: Ct_Value_Id, builder: ^strin
}
strings.write_byte(builder, ';')
return true
case .Function:
if value.index >= u64(len(state.checker.ast_module.functions)) {
return false
}
fmt.sbprintf(builder, "fn%d;", value.index)
return true
case .Slice:
item, item_ok := types.container(value.type, &state.checker.module.types)
if !item_ok || item.kind != .Slice || item.mutable || item.child != types.U8 {
@@ -2935,7 +2991,7 @@ ct_write_comptime_key :: proc(state: ^Ct_State, id: Ct_Value_Id, builder: ^strin
}
strings.write_string(builder, "o;")
return true
case .Invalid, .Void, .Undefined, .Range, .Pointer, .Function, .Fallible:
case .Invalid, .Void, .Undefined, .Range, .Pointer, .Fallible:
return false
}
return false