function values as comptime params
This commit is contained in:
@@ -596,6 +596,9 @@ build_static_value :: proc(checker: ^Checker, value: Ct_Value, span: source.Span
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if value.kind == .Function {
|
||||
return build_function_value(checker, ast.Function_Id(u32(value.index)), span, expected)
|
||||
}
|
||||
if value.kind == .Array || value.kind == .Struct || value.kind == .Range {
|
||||
children := ct_child_slice(&checker.static_state, value)
|
||||
args := make([]hir.Expr_Id, len(children), checker.allocator)
|
||||
@@ -4728,7 +4731,7 @@ infer_expr :: proc(
|
||||
_ = pop(&stack)
|
||||
continue
|
||||
}
|
||||
if callee_type, handled := infer_qualified_value_field_type(checker, expr, locals, pkg, file); handled {
|
||||
if callee_type, handled := infer_qualified_value_field_type(checker, expr, locals, pkg, file, demanded); handled {
|
||||
_, function_item, function_type, ok := types.function_pointer(callee_type, &checker.module.types)
|
||||
if !ok {
|
||||
last = types.INVALID
|
||||
@@ -4757,6 +4760,19 @@ infer_expr :: proc(
|
||||
callee_type := types.INVALID
|
||||
if !symbol.is_valid(expr.qualifier) {
|
||||
callee_type = find_infer_local(locals, expr.name)
|
||||
if !types.is_valid(callee_type) {
|
||||
if value, ok := current_comptime_value(checker, expr.name); ok && value.kind == .Static {
|
||||
callee_type = value.type
|
||||
if value.static_value != INVALID_CT_VALUE && int(value.static_value) < len(checker.static_state.values) {
|
||||
function_value := checker.static_state.values[value.static_value]
|
||||
if function_value.kind == .Function {
|
||||
_, _, _ = function_pointer_type_for_template(
|
||||
checker, ast.Function_Id(u32(function_value.index)), demanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !types.is_valid(callee_type) && available {
|
||||
global := find_global(checker, expr.name, target_pkg, expr_lookup_file(expr, file))
|
||||
@@ -6690,12 +6706,24 @@ infer_qualified_value_field_type :: proc(
|
||||
locals: []Infer_Local,
|
||||
pkg: ast.Package_Id,
|
||||
file: ast.File_Id,
|
||||
demanded: ^[dynamic]Spec_Id = nil,
|
||||
) -> (types.Type, bool) {
|
||||
if !symbol.is_valid(expr.qualifier) ||
|
||||
find_import(checker, file, expr.qualifier) != ast.INVALID_IMPORT {
|
||||
return types.INVALID, false
|
||||
}
|
||||
base_type := find_infer_local(locals, expr.qualifier)
|
||||
if !types.is_valid(base_type) {
|
||||
if value, ok := current_comptime_value(checker, expr.qualifier); ok && value.kind == .Static {
|
||||
base_type = value.type
|
||||
if field_value, found := persistent_field_value(checker, value.static_value, expr.name);
|
||||
found && field_value.kind == .Function {
|
||||
_, _, _ = function_pointer_type_for_template(
|
||||
checker, ast.Function_Id(u32(field_value.index)), demanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if !types.is_valid(base_type) {
|
||||
if global := find_global(checker, expr.qualifier, pkg, file); global != ast.INVALID_GLOBAL {
|
||||
base_type = checker.global_types[global]
|
||||
@@ -8235,6 +8263,15 @@ build_expr :: proc(
|
||||
non_callable = true
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if value, ok := current_comptime_value(checker, expr.name);
|
||||
ok && value.kind == .Static && value.static_value != INVALID_CT_VALUE &&
|
||||
int(value.static_value) < len(checker.static_state.values) {
|
||||
callee = build_static_value(
|
||||
checker, checker.static_state.values[value.static_value], expr.span, types.INVALID,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if callee == hir.INVALID_EXPR && !non_callable {
|
||||
if global := find_global(checker, expr.name, target_pkg, expr_lookup_file(expr, file)); global != ast.INVALID_GLOBAL {
|
||||
@@ -8757,9 +8794,20 @@ build_expr :: proc(
|
||||
stack[frame_index].built_args = nil
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
} else {
|
||||
target := hir.INVALID_REF
|
||||
callee := frame.left
|
||||
callee_expr := checker.module.exprs[frame.left]
|
||||
if callee_expr.kind == .Function {
|
||||
function := hir.as_function(callee_expr.target)
|
||||
if function != hir.INVALID_FUNCTION {
|
||||
target = callee_expr.target
|
||||
callee = hir.INVALID_EXPR
|
||||
add_unique_function(calls, function)
|
||||
}
|
||||
}
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Call, span=expr.span, type=result, target=hir.INVALID_REF,
|
||||
left=frame.left, right=hir.INVALID_EXPR, args=stack[frame_index].built_args,
|
||||
kind=.Call, span=expr.span, type=result, target=target,
|
||||
left=callee, right=hir.INVALID_EXPR, args=stack[frame_index].built_args,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
stack[frame_index].built_args = nil
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user