function values as comptime params
This commit is contained in:
+2
-2
@@ -155,7 +155,7 @@ as `math.divfloor(a, b)` resolve to ordinary functions.
|
||||
- demand-monomorphized Brolang and C-ABI functions
|
||||
- integer comptime value parameters such as `make_array func($N usize) [N]u8`, specialized by value and omitted from the runtime ABI
|
||||
- explicit comptime type parameters such as `max func($T type, a, b T) T`, specialized by type and omitted from the runtime ABI
|
||||
- comptime parameters may appear anywhere, are erased from the runtime ABI, and accept recursively stable booleans, integers, floats, types, immutable bytes, enums, fixed arrays, records/tuples, optionals, and tagged unions; equal structural values share specializations, while pointers, functions, general slices, fallibles, ranges, untagged unions, and undefined values have no stable comptime identity
|
||||
- comptime parameters may appear anywhere, are erased from the runtime ABI, and accept recursively stable booleans, integers, floats, types, immutable bytes, enums, fixed arrays, records/tuples, optionals, tagged unions, and concrete function values; equal structural values and function declarations share specializations, while pointers, general slices, fallibles, ranges, untagged unions, and undefined values have no stable comptime identity
|
||||
- comptime parameters may be omitted when uniquely recoverable from runtime arguments, the immediate expected result, or exact type-factory provenance; `_` is an explicit inference hole
|
||||
- forced typed comptime expressions such as `$sum(1, 2)`, `$Point { x = 1, y = 2 }`, and comptime value blocks such as `${ yield 4 }`
|
||||
- comptime execution for bodyful Brolang functions with mutable locals, loops, `defer`, `match`, `try`/`catch`, pointer/slice storage mutation, pointer captures, and calls through comptime-known function values; `undefined` storage may be initialized at comptime, but remaining poison cannot be observed
|
||||
@@ -165,7 +165,7 @@ as `math.divfloor(a, b)` resolve to ordinary functions.
|
||||
- `tag!(value)` reads a tagged union's active discriminant and folds when the value is comptime-known; `tagname!(enum_value)` requires a comptime-known enum value and returns its immutable declaration name
|
||||
- bodyful `c_func` definitions and bodyless `c_func` declarations with exact external symbol names
|
||||
- concrete-only C signatures, C variadic declarations/calls, and C default argument promotions
|
||||
- native function pointer values and types with `@func(...) R`, fallible `@func(...) R ! E`, optional `?@func(...) R`, and non-variadic native indirect calls
|
||||
- native function pointer values and types with `@func(...) R`, fallible `@func(...) R ! E`, optional `?@func(...) R`, comptime specialization by declaration identity, and non-variadic native indirect calls when the target is not statically known
|
||||
- Apple Silicon C ABI lowering for scalars, pointers, fixed-signature plain records/unions, small aggregates, homogeneous float aggregates, and indirect aggregate returns
|
||||
- imported C typedefs, scalar constants, enum constants, fixed arrays, complete plain structs/unions, C `void*` as nullable `anyopaque` pointers, and pointers to opaque records
|
||||
- imported external C object variables, including mutable variables and immutable object globals
|
||||
|
||||
@@ -226,7 +226,7 @@ Current prototype features:
|
||||
- Plain imported C structs/unions, fixed arrays, and C function pointer typedefs, including keyed literals, field access, callbacks, and Apple Silicon by-value ABI lowering
|
||||
- Qualified imported globals and functions with package-aware symbol mangling
|
||||
- Demand-monomorphized Brolang and C-ABI functions
|
||||
- Recursively stable comptime values—including booleans, integers, floats, types, immutable bytes, enums, fixed arrays, records/tuples, optionals, and tagged unions—may be interleaved with runtime parameters, are erased from the ABI, and specialize from explicit arguments or exact inference provenance
|
||||
- Recursively stable comptime values—including booleans, integers, floats, types, immutable bytes, enums, fixed arrays, records/tuples, optionals, tagged unions, and concrete function values—may be interleaved with runtime parameters, are erased from the ABI, and specialize from explicit arguments, declaration identity, or exact inference provenance
|
||||
- Forced typed comptime expressions (`$sum(1, 2)`, `$Point { x = 1, y = 2 }`) and comptime value blocks (`${ yield 4 }`)
|
||||
- Zig-style comptime type factories returning anonymous native structs (`Box func($T type) type`, used as `Box(i32)`)
|
||||
- Comptime execution for bodyful Brolang functions with mutable locals, loops, `defer`/`errdefer`, `match`, `try`/`catch`, pointer/slice storage mutation, pointer captures, and calls through comptime-known function values
|
||||
|
||||
@@ -878,7 +878,7 @@
|
||||
- equal structural values reuse specializations and stable emitted names, distinct values
|
||||
specialize separately, aggregate inference uses exact type-factory provenance, and all
|
||||
comptime parameters remain erased from the runtime ABI
|
||||
- undefined values, pointers, functions, general slices, fallibles, ranges, and untagged
|
||||
- undefined values, pointers, general slices, fallibles, ranges, and untagged
|
||||
unions diagnose that they have no stable comptime identity
|
||||
- `@std/meta.TypeInfo.enum` carries declaration-ordered `EnumInfo.fields`, enabling enum
|
||||
formatting through `field!` without runtime reflection metadata
|
||||
@@ -913,6 +913,14 @@
|
||||
- native unsigned scalars and target-classified unsigned C scalars satisfy the constraint
|
||||
- `isize` and `usize` remain concrete pointer-sized types
|
||||
|
||||
43. comptime function parameters (implemented)
|
||||
- concrete native and C function values, function literals, and aggregates containing them
|
||||
specialize by declaration identity rather than runtime address
|
||||
- repeated declarations reuse specializations, distinct declarations specialize separately, and
|
||||
function-valued parameters remain erased from the runtime ABI
|
||||
- statically known callback invocations lower to direct calls; runtime-selected function pointers
|
||||
remain indirect, and bodyless C declarations remain runtime-only during comptime execution
|
||||
|
||||
## A word on unchecked casts
|
||||
|
||||
For casts that bypass safety checks, Honey provides builtin functions:
|
||||
|
||||
@@ -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
|
||||
|
||||
+91
-4
@@ -2789,9 +2789,7 @@ milestone_39_rejects_values_without_stable_identity :: proc(t: ^testing.T) {
|
||||
text := `BadUnion :: union { number i32, flag bool }
|
||||
Config :: struct { value i32 }
|
||||
|
||||
identity func() i32 { return 1 }
|
||||
reject_pointer func($value @i32) void {}
|
||||
reject_function func($value @func() i32) void {}
|
||||
reject_slice func($value []i32) void {}
|
||||
reject_range func($value range) void {}
|
||||
reject_union func($value BadUnion) void {}
|
||||
@@ -2802,7 +2800,6 @@ items [2]i32 :: [1, 2]
|
||||
|
||||
main func() void {
|
||||
reject_pointer(&stored)
|
||||
reject_function(identity)
|
||||
reject_slice(items[..])
|
||||
reject_range(0..3)
|
||||
reject_union(BadUnion {number = 1})
|
||||
@@ -2827,7 +2824,97 @@ main func() void {
|
||||
found += 1
|
||||
}
|
||||
}
|
||||
testing.expect(t, found >= 6)
|
||||
testing.expect(t, found >= 5)
|
||||
}
|
||||
|
||||
@(test)
|
||||
comptime_function_parameters_specialize_and_lower_directly :: proc(t: ^testing.T) {
|
||||
text := `Callback_Config :: struct { call @func(value i32) i32 }
|
||||
|
||||
increment func(value i32) i32 { return value + 1 }
|
||||
decrement func(value i32) i32 { return value - 1 }
|
||||
external c_func(value i32) i32
|
||||
|
||||
apply func($callback @func(value i32) i32, value i32) i32 {
|
||||
return callback(value)
|
||||
}
|
||||
|
||||
apply_c func($callback *c_func(value i32) i32, value i32) i32 {
|
||||
return callback(value)
|
||||
}
|
||||
|
||||
apply_config func($config Callback_Config, value i32) i32 {
|
||||
return config.call(value)
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
a i32 :: apply(increment, 1)
|
||||
b i32 :: apply(increment, 2)
|
||||
c i32 :: apply(decrement, 3)
|
||||
d i32 :: apply(func(value i32) i32 { return value + 2 }, 4)
|
||||
e i32 :: apply_c(external, 5)
|
||||
f i32 :: apply_config(Callback_Config {call = increment}, 6)
|
||||
return a + b + c + d + e + f
|
||||
}
|
||||
`
|
||||
stable_names: [dynamic]string
|
||||
defer {
|
||||
for name in stable_names {
|
||||
delete(name)
|
||||
}
|
||||
delete(stable_names)
|
||||
}
|
||||
for pass := 0; pass < 2; pass += 1 {
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
symbols := symbol.init_table()
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
ir_module := lower.lower(&hir_module)
|
||||
|
||||
apply_count := 0
|
||||
callback_specializations := 0
|
||||
for function in ir_module.functions {
|
||||
plain_apply := strings.contains(function.link_name, "bro__p0__apply__")
|
||||
callback_specialization := plain_apply ||
|
||||
strings.contains(function.link_name, "bro__p0__apply_c__") ||
|
||||
strings.contains(function.link_name, "bro__p0__apply_config__")
|
||||
if !callback_specialization {
|
||||
continue
|
||||
}
|
||||
if plain_apply {
|
||||
apply_count += 1
|
||||
}
|
||||
if pass == 0 {
|
||||
append(&stable_names, strings.clone(function.link_name))
|
||||
} else {
|
||||
testing.expect_value(t, function.link_name, stable_names[callback_specializations])
|
||||
}
|
||||
callback_specializations += 1
|
||||
testing.expect_value(t, len(function.param_types), 1)
|
||||
found_direct_call := false
|
||||
for instruction in function.instructions {
|
||||
testing.expect(t, instruction.op != .Function_Address)
|
||||
if instruction.op == .Call {
|
||||
testing.expect(t, ir.as_function(instruction.target) != ir.INVALID_FUNCTION)
|
||||
found_direct_call = true
|
||||
}
|
||||
}
|
||||
testing.expect(t, found_direct_call)
|
||||
}
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect_value(t, apply_count, 3)
|
||||
testing.expect_value(t, callback_specializations, 5)
|
||||
|
||||
ir.destroy_module(&ir_module)
|
||||
hir.destroy_module(&hir_module)
|
||||
ast.destroy_module(&ast_module)
|
||||
delete(stream.items)
|
||||
symbol.destroy_table(&symbols)
|
||||
source.destroy_diagnostics(&diagnostics)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
|
||||
@@ -9,6 +9,10 @@ Point :: struct {
|
||||
y i32
|
||||
}
|
||||
|
||||
Callback_Config :: struct {
|
||||
call @func(value i32) i32
|
||||
}
|
||||
|
||||
Box :: union(enum) {
|
||||
point Point
|
||||
empty void
|
||||
@@ -78,6 +82,26 @@ increment func(value i32) i32 {
|
||||
return value + 1
|
||||
}
|
||||
|
||||
double func(value i32) i32 {
|
||||
return value * 2
|
||||
}
|
||||
|
||||
decrement_c c_func(value i32) i32 {
|
||||
return value - 1
|
||||
}
|
||||
|
||||
apply_comptime func($callback @func(value i32) i32, value i32) i32 {
|
||||
return callback(value)
|
||||
}
|
||||
|
||||
apply_comptime_c func($callback *c_func(value i32) i32, value i32) i32 {
|
||||
return callback(value)
|
||||
}
|
||||
|
||||
apply_comptime_config func($config Callback_Config, value i32) i32 {
|
||||
return config.call(value)
|
||||
}
|
||||
|
||||
call_native func(callback @func(value i32) i32, value i32) i32 {
|
||||
return callback(value)
|
||||
}
|
||||
@@ -180,6 +204,10 @@ main func() i32 {
|
||||
recovered i32 :: $recover()
|
||||
storage i32 :: $storage_mutation()
|
||||
called i32 :: $call_native(increment, 11)
|
||||
comptime_callback i32 :: $apply_comptime(increment, 12)
|
||||
comptime_literal i32 :: $apply_comptime(func(value i32) i32 { return value + 2 }, 12)
|
||||
comptime_c_callback i32 :: $apply_comptime_c(decrement_c, 15)
|
||||
comptime_config i32 :: $apply_comptime_config(Callback_Config {call = increment}, 15)
|
||||
fallible_ok i32 :: $call_fallible(may_fail, false) catch 0
|
||||
fallible_err i32 :: $call_fallible(may_fail, true) catch |e| {
|
||||
result i32 :: match e {
|
||||
@@ -239,5 +267,20 @@ main func() i32 {
|
||||
if ERRDEFER != 42 {
|
||||
return 17
|
||||
}
|
||||
if comptime_callback != 13 or comptime_literal != 14 or
|
||||
comptime_c_callback != 14 or comptime_config != 16 {
|
||||
return 18
|
||||
}
|
||||
if apply_comptime(increment, 20) != 21 or apply_comptime(increment, 21) != 22 or
|
||||
apply_comptime(double, 20) != 40 {
|
||||
return 19
|
||||
}
|
||||
if apply_comptime(func(value i32) i32 { return value + 3 }, 20) != 23 {
|
||||
return 20
|
||||
}
|
||||
if apply_comptime_c(decrement_c, 20) != 19 or
|
||||
apply_comptime_config(Callback_Config {call = increment}, 20) != 21 {
|
||||
return 21
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user