Files
honey/tests/native.py
T
hl-valdemar cc39c96fc0 feat: materialize address-free compile-time untagged unions
Snapshot full union storage rather than choosing an overlapping field. Preserve structural union source syntax independently of nominal identity so direct literal arguments materialize and share normalized specialization keys. Reject uninitialized bytes and address-bearing member layouts.
2026-10-30 16:35:11 +01:00

10663 lines
398 KiB
Python

"""Build Honey first with `bro build`, then run `python3 tests/native.py`."""
import os
from pathlib import Path
import subprocess
import tempfile
import textwrap
ROOT = Path(__file__).resolve().parents[1]
HONEY = ROOT / "build/honey"
# Explicit expectations guard against frontend bugs shared by both execution paths.
CASES = {
"unreachable_is_a_demanded_source_trap_without_cleanup": (
"""
fail proc() i16 {
defer unreachable
unreachable
}
main proc() i16 { return fail() }
""", b"", b":3:5: runtime trap: reached unreachable statement",
),
"untaken_and_unused_unreachable_do_not_diagnose": (
"""
unused proc() i16 { unreachable }
choose proc(flag bool) i16 {
if (flag) unreachable
return match flag { true: unreachable, false: 42 }
}
main proc() i16 { return choose(false) }
""", b"42\n", None,
),
"unreachable_traps_only_selected_constant_execution": (
"""
choose proc(flag bool) i16 {
if (flag) unreachable
return 42
}
main proc() i16 { return $(choose(false)) }
""", b"42\n", None,
),
"unreachable_constant_execution_preserves_source": (
"""
fail proc() i16 {
unreachable
}
main proc() i16 { return $(fail()) }
""", b"", b":2:5: runtime trap: reached unreachable statement",
),
"terminal_while_true_preserves_nested_breaks_and_cleanups": (
"""
compute proc(trace @mut i16) i16 {
while true {
defer trace^ += 1
while true { break }
if (trace^ == 2) return 42
continue
}
}
main proc() [2]i16 {
trace i16 := 0
answer :: compute(&trace)
return [answer, trace]
}
""", b"[42, 3]\n", None,
),
"terminal_while_true_return": (
"main proc() i16 { while true { return 42 } }",
b"42\n", None,
),
"terminal_while_true_constant_execution": (
"compute proc() i16 { while true { return 42 } }\nmain proc() i16 { return $(compute()) }",
b"42\n", None,
),
"terminal_while_true_ignores_break_after_return": (
"main proc() i16 { while true { return 42\nbreak } }",
b"42\n", None,
),
"while_true_break_requires_return": (
"main proc() i16 { while true { break } }",
b"", b"nonvoid function can finish without returning a value",
),
"while_true_value_block_break_requires_return": (
"""
main proc() i16 {
while true {
value i16 :: { break }
_ = value
}
}
""", b"", b"nonvoid function can finish without returning a value",
),
"while_runtime_guard_still_requires_return": (
"main proc() i16 { flag := true\nwhile flag { return 42 } }",
b"42\n", b"nonvoid function can finish without returning a value",
),
"unreachable_rejects_trailing_operand": (
"main proc() i16 { unreachable 42 }",
b"", b"unexpected token",
),
"distinct_bitwise_results_preserve_nominal_type": (
"""
Flags :: distinct u16
Signed :: distinct i8
exact proc(value Flags) Flags { return value }
main proc() [4]i16 {
flags Flags := 21
flags <<= u8(1)
flags xor= 3
flags &= 63
flags |= 2
signed Signed := -3
signed >>= u64(1)
return [i16(exact(flags)), i16(~Flags(65500)),
i16(signed), i16(Signed(-2) <<| 7)]
}
""", b"[43, 35, -2, -128]\n", None,
),
"compound_updates_evaluate_places_once_before_rhs": (
"""
Box :: struct { values [2]mut i16 }
place proc(box @mut Box, trace @mut i16) @mut i16 {
trace^ = trace^ * 10 + 1
return &box.values[0]
}
rhs proc(box @mut Box, trace @mut i16) i16 {
trace^ = trace^ * 10 + 2
box.values[0] = 100
return 2
}
index proc(trace @mut i16) usize {
trace^ = trace^ * 10 + 3
return 1
}
main proc() [4]i16 {
box Box := { values = [40, 6] }
trace i16 := 0
place(&box, &trace)^ += rhs(&box, &trace)
box.values[index(&trace)] *= 7
count i16 := 0
for (0..3) |_| { defer count += 1 }
return [box.values[0], box.values[1], trace, count]
}
""", b"[42, 42, 123, 3]\n", None,
),
"compound_bitwise_and_float_updates": (
"""
main proc() [4]i16 {
value u8 := 255
value &= 15
value xor= 3
value |= 1
value <<= 1
value >>= 1
value <<|= u64(1000)
number i16 := 20
number += 3
number -= 2
number *= 2
real f64 := 84
real /= 2
return [i16(value), number, i16(real), i16(~u8(213))]
}
""", b"[255, 42, 42, 42]\n", None,
),
"bitwise_precedence_and_type_composition": (
"""
A :: enum { first }
B :: enum { second }
Error :: A | B
fail proc() i16 ! Error { return .first }
main proc() [3]i16 {
return [i16(u8(1) | 2 xor 3 & 6), i16(u8(3) << (1 + 1)),
fail() catch |error| match error { .first: 42, .second: 0 }]
}
""", b"[0, 12, 42]\n", None,
),
"bitwise_constants_and_type_producer_updates": (
"""
Fixed proc() type {
counts [2]mut usize := [1, 2]
counts[0] <<= 2
counts[1] |= 1
total usize := counts[0]
total += counts[1]
return struct { values [total]i16, answer i16 = i16(~u8(213)) }
}
compute proc() u8 {
value u8 := 21
value <<= 1
return value
}
choose proc($value u8) i16 {
if ((value & 3) == 2) return 42
else return missing_member(value)
}
main proc() [4]i16 {
generated Fixed() :: { values = [0, 0, 0, 0, 0, 0, 0] }
array [(usize(1) << 2)]i16 :: [0, 0, 0, 0]
return [generated.answer, i16($(compute())), choose($(u8(21) << 1)),
i16(generated.values.len + array.len)]
}
missing_member proc(value u8) bool { return true }
""", b"[42, 42, 42, 11]\n", None,
),
"compound_signed_overflow": (
"main proc() i8 { value i8 := 127\nvalue += 1\nreturn value }",
b"", b"integer arithmetic overflow",
),
"compound_readonly_place": (
"main proc() i16 { values [1]i16 := [40]\nvalues[0] += 2\nreturn 0 }",
b"", b"indexed assignment requires a writable array element",
),
"bitwise_float_rejected": (
"main proc() f64 { return f64(1) & 2 }",
b"", b"operator requires compatible operand types",
),
"shift_signed_count_rejected": (
"main proc() i16 { return i16(1) << i16(2) }",
b"", b"operator requires compatible operand types",
),
"shift_known_count_rejected_even_untaken": (
"main proc() i16 { if (false) { _ = u8(1) << 8 }\nreturn 42 }",
b"42\n", b"shift count must be smaller than the integer bit width",
),
"shift_runtime_count_traps": (
"shift proc(count u64) u8 { return u8(1) << count }\nmain proc() u8 { return shift(256) }",
b"", b"shift count must be smaller than the integer bit width",
),
"yielding_blocks_nest_and_copy_before_scoped_cleanup": (
"""
Item :: struct { values [1]mut i16 }
main proc() [3]i16 {
trace i16 := 0
source Item := { values = [40] }
saved Item :: {
defer trace = trace * 10 + 1
inner i16 :: {
defer trace = trace * 10 + 2
yield 2
}
{
defer source.values[0] = 0
source.values[0] = source.values[0] + inner
yield source
}
trace = -1
}
return [saved.values[0], source.values[0], trace]
}
""", b"[42, 0, 21]\n", None,
),
"yielding_blocks_preserve_loop_and_function_transfers": (
"""
choose proc(flag bool) i16 {
value i16 :: {
if (flag) return 7
yield 42
}
return value
}
main proc() [3]i16 {
total i16 := 0
cleanups i16 := 0
for (0..5) |index| {
value i16 :: {
defer cleanups = cleanups + 1
if (index == 0) continue
if (index == 3) break
yield i16(index)
}
total = total + value
}
return [total, cleanups, choose(true) + choose(false)]
}
""", b"[3, 4, 49]\n", None,
),
"yielding_blocks_leave_inner_loops_on_yield": (
"""
main proc() [2]i16 {
cleanups i16 := 0
value i16 :: {
for (0..3) |index| {
defer cleanups = cleanups + 1
if (index == 0) continue
yield 42
}
yield 0
}
return [value, cleanups]
}
""", b"[42, 2]\n", None,
),
"yielding_match_catch_and_conditional_blocks_are_lazy": (
"""
Error :: enum { failed }
fail proc(flag bool) i16 ! Error {
if (flag) return .failed
return 40
}
choose proc(flag bool) i16 {
return match flag {
true: { value :: fail(false) catch { yield 0 }
yield value + 2 },
false: { yield fail(true) catch { yield 7 } },
}
}
main proc() [3]i16 {
return [choose(true), choose(false),
if (true) { yield 42 } else { yield divtrunc!(1, 0) }]
}
""", b"[42, 7, 42]\n", None,
),
"yielding_blocks_contextual_optional_fallible_and_aggregate_values": (
"""
Error :: enum { failed }
Item :: struct { value i16 }
optional proc(flag bool) ?i16 {
return { if (flag) yield 42
yield null }
}
fallible proc(flag bool) i16 ! Error {
return { if (flag) yield 42
yield .failed }
}
item proc(flag bool) Item {
return if (flag) { yield { value = 42 } } else { value = 7 }
}
main proc() [4]i16 {
if (optional(false) != null) return [0, 0, 0, 0]
return [optional(true)?, fallible(true) catch 0,
fallible(false) catch { yield 7 }, item(true).value]
}
""", b"[42, 42, 7, 42]\n", None,
),
"yielding_blocks_propagate_errors_and_run_only_reached_cleanup": (
"""
Error :: enum { failed }
fail proc() i16 ! Error { return .failed }
compute proc(trace @mut i16, flag bool) i16 ! Error {
value i16 :: {
defer trace^ = trace^ * 10 + 1
errdefer trace^ = trace^ * 10 + 2
if (flag) yield 42
yield try fail()
}
return value
}
main proc() [4]i16 {
success i16 := 0
failure i16 := 0
left :: compute(&success, true) catch 0
right :: compute(&failure, false) catch 7
return [left, right, success, failure]
}
""", b"[42, 7, 1, 21]\n", None,
),
"yielding_blocks_preserve_narrow_types_and_compile_time_values": (
"""
exact proc(value i8) i16 { return i16(value) }
compute proc() i8 {
return {
total i8 := 0
for (i8(0)..i8(3)) |index| total = total + index
yield total + 39
}
}
main proc() [3]i16 {
return [exact({ yield i8(42) }), i16($(compute())),
i16($({ value i8 :: 7
yield value }))]
}
""", b"[42, 42, 7]\n", None,
),
"yielding_blocks_generate_types_defaults_and_specialized_bodies": (
"""
Choose proc(wide bool) type {
return {
Selected := i8
if (wide) Selected = i16
yield Selected
}
}
Box proc(wide bool) type {
count usize :: { yield if (wide) 2 else 1 }
return struct {
values [count]Choose(wide)
bias i16 = { yield 7 }
}
}
select proc($flag bool, value i16) i16 {
return { if (flag) yield value
yield compile_error!("unselected") }
}
main proc() [3]i16 {
value Box(true) :: { values = [40, 2] }
return [select(true, value.values[0] + value.values[1]),
value.bias, i16(value.values.len)]
}
""", b"[42, 7, 2]\n", None,
),
"yielding_blocks_keep_match_and_catch_capture_scopes": (
"""
Choice :: union(enum) { value i8, empty void }
Error :: union(enum) { failed i8 }
fail proc() i16 ! Error { return .failed{7} }
choose proc(value Choice) i16 {
return match value {
.value |payload|: { yield i16(payload) },
.empty: { yield fail() catch |error| {
yield match error {
.failed |code|: { yield i16(code) },
}
} },
}
}
main proc() [2]i16 { return [choose(.value{42}), choose(.empty)] }
""", b"[42, 7]\n", None,
),
"yielding_blocks_allow_local_yields_inside_cleanup": (
"""
main proc() i16 {
value i16 := 0
{
defer value = { yield 42 }
}
return value
}
""", b"42\n", None,
),
"yielding_blocks_require_yield_operands": (
"main proc() i16 { return { yield } }",
b"", b"unexpected token",
),
"yielding_blocks_preserve_yield_capture_immutability": (
"""
main proc() i16 {
value ?i16 :: 42
return if value |payload| { payload = 7
yield payload } else 0
}
""", b"", b"assignment requires a mutable local binding",
),
"yielding_blocks_reject_yield_outside_value_sources": (
"main proc() i16 { yield 42 }",
b"", b"yield requires an enclosing value block",
),
"yielding_blocks_check_fallthrough_without_trapping_yielded_paths": (
"""
choose proc(flag bool) i16 {
return { if (flag) yield 42 }
}
main proc() i16 { return choose(true) }
""", b"42\n", b"nonvoid value block can finish without yielding a value",
),
"yielding_blocks_trap_reached_missing_value_paths": (
"""
choose proc(flag bool) i16 {
return { if (flag) yield 42 }
}
main proc() i16 { return choose(false) }
""", b"", b"nonvoid value block can finish without yielding a value",
),
"yielding_blocks_reject_incompatible_runtime_yields": (
"""
choose proc(flag bool) i16 {
return { if (flag) yield i16(42)
yield u8(7) }
}
main proc() i16 { return choose(true) }
""", b"42\n", b"yield does not match the value block result type",
),
"yielding_blocks_reject_outward_cleanup_yields": (
"""
main proc() i16 {
return { defer { yield 7 }
yield 42 }
}
""", b"", b"cleanup cannot",
),
"yielding_blocks_preserve_type_control_mutation_captures_and_cleanup": (
"""
Choose proc(input ?bool) type {
Selected := i8
Element :: {
Selected = i8
defer Selected = i16
for (0..3) |index| {
if (index == 1) {
yield if input |flag| { yield if (flag) bool else i8 }
else { yield i16 }
}
}
yield i8
}
return struct { flag Element, value Selected }
}
main proc() i16 {
value Choose(true) :: { flag = true, value = 42 }
return if (value.flag) value.value else 0
}
""", b"42\n", None,
),
"yielding_blocks_preserve_runtime_aliases_callbacks_and_void_results": (
"""
add proc(value i16) i16 { return value + 2 }
noop proc() void {}
nothing proc() void { return { yield noop() } }
main proc() [2]i16 {
values [1]mut i16 := [40]
pointer @mut i16 :: { yield &values[0] }
view []mut i16 :: { yield values[..] }
callback @proc(value i16) i16 :: { yield add }
pointer^ = callback(view[0])
({ yield nothing() })
return [values[0], view[0]]
}
""", b"[42, 42]\n", None,
),
"yielding_blocks_keep_compile_time_logical_guards_lazy": (
"""
Choose proc() type {
Selected := i8
if (false and { Selected = i16
yield true }) Selected = bool
if (true or { Selected = bool
yield false }) {}
return Selected
}
exact proc(value i8) i16 { return i16(value) }
main proc() i16 {
value Choose() :: 42
return exact(value)
}
""", b"42\n", None,
),
"yielding_blocks_check_skipped_compile_time_guard_result_types": (
"""
Bad proc() type {
if (false and { yield 1 }) return bool
return i16
}
main proc() Bad() { return 42 }
""", b"", b"operator requires compatible operand types",
),
"conditional_expressions_evaluate_guard_once_and_only_selected_arm": (
"""
next proc(calls @mut i16, value bool) bool { calls^ = calls^ + 1
return value }
main proc() [3]i16 {
calls i16 := 0
first i16 :: if next(&calls, true) 42 else divtrunc!(1, 0)
second i16 :: if next(&calls, false) divtrunc!(1, 0) else 7
return [first, second, calls]
}
""", b"[42, 7, 2]\n", None,
),
"conditional_expressions_nest_bind_else_and_preserve_precedence": (
"""
choose proc(a, b bool) i16 { return if (a) if (b) 1 else 40 else 3 + 4 }
main proc() [3]i16 {
return [choose(true, false) + 2, choose(false, true),
2 * (if (false) 10 else 21)]
}
""", b"[42, 7, 42]\n", None,
),
"conditional_expressions_preserve_aggregate_copy_isolation": (
"""
Item :: struct { values [1]mut i16 }
choose proc(flag bool, left, right Item) Item { return if (flag) left else right }
main proc() i16 {
left Item := { values = [42] }
right Item :: { values = [7] }
saved :: choose(true, left, right)
left.values[0] = 0
return saved.values[0]
}
""", b"42\n", None,
),
"conditional_expressions_select_generated_types_and_specialized_bodies": (
"""
Choose proc(wide bool) type { return if (wide) i16 else i8 }
length proc(flag bool) usize { return if (flag) 2 else 1 }
Box proc($wide bool) type {
return struct {
value Choose(wide)
items [length(wide)]i16
other (if (wide) i16 else i8)
}
}
select proc($flag bool, value i16) i16 {
return if $(flag) value else compile_error!("unselected")
}
main proc() [3]i16 {
value Box(true) :: { value = 40, items = [1, 2], other = 42 }
return [value.value, i16(value.items.len), select(true, value.other)]
}
""", b"[40, 2, 42]\n", None,
),
"conditional_expressions_keep_outer_match_default": (
"""
choose proc(flag bool) i16 {
return match flag {
true: (if (flag) 42
else 1)
else: 7
}
}
main proc() i16 { return choose(false) }
""", b"7\n", None,
),
"conditional_expressions_check_unselected_runtime_result_types": (
"""
choose proc(flag bool) i16 { return if (flag) i16(42) else u8(1) }
main proc() i16 { return choose(true) }
""", b"42\n", b"incompatible value type",
),
"conditional_expressions_require_else": (
"main proc() i16 { return if (true) 42 }",
b"", b"unexpected token",
),
"conditional_expressions_preserve_optional_and_fallible_result_context": (
"""
Error :: enum { failed }
optional proc(flag bool) ?i16 { return if (flag) 42 else null }
fallible proc(flag bool) i16 ! Error { return if (flag) 42 else .failed }
main proc() [3]i16 {
if (optional(false) != null) return [0, 0, 0]
return [optional(true)?, fallible(true) catch 0, fallible(false) catch 7]
}
""", b"[42, 42, 7]\n", None,
),
"conditional_expressions_materialize_direct_constants": (
"""
main proc() [2]i16 {
return [i16($(if (true) 42 else divtrunc!(1, 0))),
$(if (false) 0 else i16(7))]
}
""", b"[42, 7]\n", None,
),
"conditional_expressions_reject_nonboolean_guards": (
"main proc() i16 { return if (1) 42 else 0 }",
b"", b"incompatible value type",
),
"optional_conditional_expressions_evaluate_once_and_keep_branches_lazy": (
"""
next proc(calls @mut i16, value ?i16) ?i16 {
calls^ = calls^ + 1
return value
}
main proc() [3]i16 {
calls i16 := 0
first i16 :: if next(&calls, 42) |payload| payload else divtrunc!(1, 0)
second i16 :: if next(&calls, null) |payload| divtrunc!(payload, 0) else 7
return [first, second, calls]
}
""", b"[42, 7, 2]\n", None,
),
"optional_conditional_expressions_keep_nested_presence_and_else_binding": (
"""
identity proc($T type, value T) T { return value }
choose proc(value ??i16) i16 {
return if value |inner| if identity(inner) |payload| payload else 7 else 3
}
main proc() [3]i16 {
return [choose(some!(null)), choose(null), choose(some!(some!(42)))]
}
""", b"[7, 3, 42]\n", None,
),
"optional_conditional_expressions_snapshot_aggregate_payloads": (
"""
Item :: struct { values [1]mut i16 }
replace proc(value @mut ?Item) i16 {
value^ = Item { values = [0] }
return 0
}
main proc() [2]i16 {
original ?Item := Item { values = [42] }
saved i16 :: if original |payload| replace(&original) + payload.values[0] else -1
return [saved, (original?).values[0]]
}
""", b"[42, 0]\n", None,
),
"optional_conditional_expressions_preserve_narrow_payload_types": (
"""
identity proc($T type, value T) T { return value }
exact proc(value i8) i16 { return i16(value) }
choose proc(value ?i8) i16 { return if value |payload| exact(identity(payload)) else 7 }
main proc() [2]i16 { return [choose(42), choose(null)] }
""", b"[42, 7]\n", None,
),
"optional_conditional_expressions_capture_pointer_callback_slice_and_zero_size": (
"""
increment proc(value i16) i16 { return value + 2 }
read_pointer proc(value ?@i16) i16 { return if value |pointer| pointer^ else 7 }
invoke proc(value ?@proc(value i16) i16) i16 {
return if value |callback| callback(40) else 8
}
sum proc(value ?[]i16) i16 {
return if value |items| items[0] + items[1] else 9
}
empty proc(value ?[0]i16) i16 { return if value |items| i16(items.len) else 10 }
main proc() [8]i16 {
value i16 :: 42
items [2]i16 :: [19, 23]
return [read_pointer(&value), read_pointer(null), invoke(increment), invoke(null),
sum(items[..]), sum(null), empty([]), empty(null)]
}
""", b"[42, 7, 42, 8, 42, 9, 0, 10]\n", None,
),
"optional_conditional_expressions_preserve_optional_and_fallible_context": (
"""
Error :: enum { failed }
optional proc(value ?i16) ?i16 { return if value |payload| payload + 2 else null }
fallible proc(value ?i16) i16 ! Error {
return if value |payload| payload + 2 else .failed
}
main proc() [3]i16 {
if (optional(null) != null) return [0, 0, 0]
return [optional(40)?, fallible(40) catch 0, fallible(null) catch 7]
}
""", b"[42, 42, 7]\n", None,
),
"optional_conditional_expressions_materialize_compile_time_scalars": (
"""
choose proc(value ?i8) i16 { return if value |payload| i16(payload) + 2 else 7 }
nested proc(value ??i16) i16 {
return if value |inner| if inner |payload| payload else 11 else 13
}
main proc() [4]i16 {
return [$(choose(40)), $(choose(null)), $(nested(some!(null))), $(nested(null))]
}
""", b"[42, 7, 11, 13]\n", None,
),
"optional_conditional_expressions_generate_types_and_captured_defaults": (
"""
Choose proc(value ?usize) type { return if value |_| i16 else i8 }
Box proc(count ?usize) type {
return if count |length| struct { values [length]i16, bias i16 = i16(length) }
else struct { value i16 = 7 }
}
main proc() [3]i16 {
first Box(2) :: { values = [19, 21] }
same Box(usize(2)) :: first
absent Box(null) :: {}
narrow Choose(null) :: 5
wide Choose(2) :: 40
return [same.values[0] + same.values[1] + same.bias, absent.value,
wide + i16(narrow)]
}
""", b"[42, 7, 45]\n", None,
),
"optional_conditional_expressions_own_compile_time_aggregate_captures": (
"""
Config :: struct { name string, counts [2]usize }
Storage proc(config ?Config) type {
return if config |payload| struct {
items [payload.counts[0]]i16
name string = payload.name
} else struct { value i16 = 7 }
}
main proc() i16 {
value Storage(Config { name = "abc", counts = [2, 1] }) :: { items = [19, 20] }
return value.items[0] + value.items[1] + i16(value.name.len)
}
""", b"42\n", None,
),
"optional_conditional_expressions_specialize_selected_capture_only": (
"""
present proc($value ?i8) i16 {
return if $(value) |payload| i16(payload) + 2 else compile_error!("absent")
}
absent proc($value ?i8) i16 {
return if $(value) |_| compile_error!("present") else 7
}
select proc($value ?i8) i16 {
return if $(value) |payload| i16(payload) + 2 else 7
}
main proc() [6]i16 {
return [present(40), absent(null), select(40), select(null), select(1), select(40)]
}
""", b"[42, 7, 42, 7, 3, 42]\n", None,
),
"optional_conditional_expressions_keep_compile_time_narrow_overflow": (
"""
narrow proc(value ?i8) i8 { return if value |payload| payload + 1 else 0 }
main proc() i8 { return $(narrow(127)) }
""", b"", b"integer arithmetic overflow",
),
"optional_conditional_expressions_reject_runtime_explicit_comptime_subject": (
"""
choose proc(value ?i16) i16 { return if $(value) |payload| payload else 0 }
main proc() i16 { return choose(42) }
""", b"", b"generic argument must be a compile-time value",
),
"optional_conditional_expressions_reject_nonoptional_subject": (
"main proc() i16 { return if true |payload| 42 else 0 }",
b"", b"condition",
),
"optional_conditional_expressions_capture_does_not_reach_else": (
"main proc() i16 { value ?i16 :: null\nreturn if value |payload| 42 else payload }",
b"", b"unknown name",
),
"optional_conditional_expressions_capture_does_not_escape": (
"""
main proc() i16 {
value ?i16 :: 42
saved i16 :: if value |payload| payload else 0
return saved + payload
}
""", b"", b"unknown name",
),
"optional_conditional_expressions_reject_capture_shadowing": (
"main proc() i16 { value ?i16 :: 42\nreturn if value |value| value else 0 }",
b"", b"duplicate name or forbidden shadowing",
),
"optional_conditional_expressions_check_unselected_result_types": (
"""
choose proc(value ?i16) i16 { return if value |payload| payload else u8(7) }
main proc() i16 { return choose(42) }
""", b"42\n", b"incompatible value type",
),
"optional_conditional_expressions_require_else": (
"main proc() i16 { value ?i16 :: 42\nreturn if value |payload| payload }",
b"", b"unexpected token",
),
"optional_conditional_expressions_reject_pointer_capture_syntax": (
"main proc() i16 { value ?i16 :: 42\nreturn if value |@payload| payload^ else 0 }",
b"", b"unexpected token",
),
"integer_divtrunc_preserves_sign_and_single_evaluation": (
"""
next proc(calls @mut i16) i16 { calls^ = calls^ + 1
return calls^ + 5 }
quotient proc(value i16) i16 { return divtrunc!(value, 3) }
main proc() [6]i16 {
calls i16 := 0
result :: divtrunc!(next(&calls), next(&calls))
return [result, calls, quotient(-7), quotient(7),
$(quotient(-7)), divtrunc!(-7, i16(-3))]
}
""", b"[0, 2, -2, 2, -2, 2]\n", None,
),
"integer_divtrunc_rejects_zero": (
"main proc() u64 { return divtrunc!(maxval!(u64), 0) }",
b"", b"integer division by zero",
),
"integer_divtrunc_checks_narrow_signed_overflow": (
"main proc() i8 { return divtrunc!(minval!(i8), -1) }",
b"", b"integer arithmetic overflow",
),
"integer_divtrunc_checks_full_width_signed_overflow": (
"main proc() i64 { return divtrunc!(minval!(i64), -1) }",
b"", b"integer arithmetic overflow",
),
"integer_divtrunc_rejects_float_operands": (
"main proc() f64 { return divtrunc!(7.0, 3.0) }",
b"", b"operator requires compatible operand types",
),
"integer_limits_reject_noninteger_types": (
"main proc() bool { return maxval!(bool) }",
b"", b"operator requires compatible operand types",
),
"integer_divtrunc_rejects_rigid_width_conflicts": (
"main proc() i16 { return divtrunc!(i8(7), i16(3)) }",
b"", b"operator requires compatible operand types",
),
"c_layout_records_and_nominal_opaque_pointers": (
"""
Handle :: opaque
Other :: opaque
Header :: c_struct { tag c_uchar, value c_ulong }
main proc() c_ulong {
header Header := { tag = 2, value = 40 }
if (sizeof!(Header) != 16 or alignof!(Header) != 8) return 0
pointer ?*mut Handle :: ptrcast!(&header)
restored *mut Header :: ptrcast!(pointer?)
return restored.value + c_ulong(restored.tag)
}
""", b"42\n", None,
),
"c_opaque_pointer_types_remain_nominal": (
"""
Left :: opaque
Right :: opaque
consume proc(value ?*Left) bool { return value == null }
main proc() bool { value ?*Right :: null
return consume(value) }
""", b"", b"incompatible value type",
),
"runtime_undefined_nested_storage_and_copy_isolation": (
"""
Item :: struct { values [2]mut i16, label string }
fill proc() Item {
item Item := undefined
for (usize(0)..item.values.len) |i| { item.values[i] = i16(i) + 19 }
item.label = "yes"
return item
}
main proc() i16 {
item := fill()
saved :: item
pointer :: &item
pointer.values[0] = 0
return saved.values[0] + saved.values[1] + i16(saved.label.len)
}
""", b"42\n", None,
),
"ordinary_constant_procedures_fill_undefined_arrays": (
"""
values proc() [2]mut i16 {
result [2]mut i16 := undefined
for (usize(0)..result.len) |i| { result[i] = i16(i) + 20 }
return result
}
main proc() i16 { result :: $(values())
return result[0] + result[1] + 1 }
""", b"42\n", None,
),
"ordinary_constants_reject_partial_undefined_snapshots": (
"""
values proc() [2]mut i16 {
result [2]mut i16 := undefined
result[0] = 42
saved :: result
result[1] = 0
return saved
}
main proc() [2]mut i16 { return $(values()) }
""", b"", b"read before initialization",
),
"ordinary_constants_reject_undefined_optional_presence": (
"""
missing proc() ?i16 { value ?i16 := undefined
return value }
main proc() ?i16 { return $(missing()) }
""", b"", b"read before initialization",
),
"ordinary_constants_reject_undefined_union_tags": (
"""
Choice :: union(enum) { value i16, empty void }
missing proc() Choice { value Choice := undefined
return value }
main proc() Choice { return $(missing()) }
""", b"", b"read before initialization",
),
"undefined_zero_leaf_shapes_cross_runtime_and_constant_calls": (
"""
empty proc() [2]mut [0]i16 {
rows [2]mut [0]i16 := undefined
return rows
}
main proc() usize {
runtime :: empty()
constant :: $(empty())
return runtime.len + constant.len
}
""", b"4\n", None,
),
"some_nested_present_null_survives_constant_roundtrip": (
"""
nested proc() ??i16 { return some!(null) }
present proc() ??i16 { return some!(some!(42)) }
main proc() i16 {
first ??i16 :: $(nested())
second ??i16 :: $(present())
absent ??i16 :: null
if (first == null or first? != null or absent != null) return -1
return second??
}
""", b"42\n", None,
),
"some_optional_specialization_keys_preserve_every_presence_layer": (
"""
Box proc($value ??i16) type { return struct { value ??i16 = value } }
main proc() i16 {
empty Box(null) :: {}
nested Box(some!(null)) :: {}
present Box(some!(some!(42))) :: {}
same Box(some!(some!(42))) :: present
if (empty.value != null or nested.value == null or nested.value? != null) return -1
if (Box(null) == Box(some!(null))) return -2
if (Box(some!(some!(42))) == Box(some!(some!(41)))) return -3
return same.value??
}
""", b"42\n", None,
),
"generic_contextual_literals_use_rigid_arguments_in_either_order": (
"""
Key :: enum { first, last }
choose proc($T type, value T, anchor @T) T { return value }
payload proc($T type, anchor @T, value struct { item T }) T { return value.item }
main proc() i16 {
key Key :: .first
selected :: choose(.last, &key)
other :: payload(&key, { item = .first })
return match selected { .last: match other { .first: 42, else: 0 }, else: 0 }
}
""", b"42\n", None,
),
"expected_result_inference_direct_return_without_runtime_arguments": (
"""
answer proc($T type) T { return 42 }
main proc() i16 { return answer() }
""", b"42\n", None,
),
"expected_result_inference_assignment_return_and_nested_parameters": (
"""
answer proc($T type) T { return 42 }
identity proc($T type, value T) T { return value }
read proc() i16 { return identity(42) }
consume proc(value i16) i16 { return value }
main proc() [4]i16 {
value i16 := identity(0)
value = answer()
return [value, read(), consume(identity(42)), consume(identity(answer()))]
}
""", b"[42, 42, 42, 42]\n", None,
),
"expected_result_inference_nested_aggregate_fields_and_elements": (
"""
identity proc($T type, value T) T { return value }
answer proc($T type) T { return 42 }
Inner :: struct { value i16 }
Outer :: struct { rows [2]Inner }
main proc() [2]i16 {
result Outer :: { rows = [{ value = identity(42) }, { value = answer() }] }
return [result.rows[0].value, result.rows[1].value]
}
""", b"[42, 42]\n", None,
),
"expected_result_inference_precedes_contextual_literal_defaults": (
"""
Key :: enum { first, last }
Record :: struct { value i16 }
identity proc($T type, value T) T { return value }
main proc() i16 {
number u8 :: identity(42)
key Key :: identity(.last)
record Record :: identity({ value = 42 })
absent ?i16 :: identity(null)
text []u8 :: identity("ab")
if (number != 42 or key != .last or absent != null or text.len != 2) return -1
return record.value
}
""", b"42\n", None,
),
"expected_result_inference_generated_nominal_type_and_value_arguments": (
"""
Box proc($T type, $count usize) type {
return struct { value T, length usize = count }
}
create proc($T type, $count usize, value T) Box(T, count) {
return { value = value }
}
main proc() i16 {
box Box(i16, 2) :: create(40)
explicit Box(i16, 2) :: create(i16, 2, 40)
if (box.value != explicit.value or box.length != 2) return -1
return box.value + i16(box.length)
}
""", b"42\n", None,
),
"expected_result_inference_optional_and_fallible_success_contexts": (
"""
Error :: enum { failed }
identity proc($T type, value T) T { return value }
optional proc() ?i16 { return identity(42) }
fallible proc() i16 ! Error { return identity(42) }
main proc() [2]i16 { return [optional()?, fallible() catch 0] }
""", b"[42, 42]\n", None,
),
"expected_result_inference_match_arms_and_value_block_yields": (
"""
answer proc($T type) T { return 42 }
choose proc(flag bool) i16 {
return match flag {
true: answer(),
false: { yield answer() },
}
}
main proc() [2]i16 { return [choose(true), choose(false)] }
""", b"[42, 42]\n", None,
),
"expected_result_inference_inside_compile_time_type_producers": (
"""
answer proc($T type) T { return 2 }
Fixed proc() type {
count usize :: answer()
return [count]i16
}
main proc() Fixed() { return [19, 23] }
""", b"[19, 23]\n", None,
),
"expected_result_inference_cleanup_comptime_and_expression_contexts": (
"""
Error :: enum { failed }
answer proc($T type) T { return 21 }
fail proc($T type) T ! Error { return .failed }
recover proc() i16 { return fail() catch |error| { yield answer() } }
propagate proc() i16 ! Error { return try fail() }
Default :: struct { value i16 = answer() }
main proc() [7]i16 {
value ?i16 :: some!(answer())
constant i16 :: $(answer())
defaults Default :: {}
return [answer() + answer(), -answer(), ~answer(), fail() catch answer(),
recover(), (value?), constant + defaults.value]
}
""", b"[42, -21, -22, 21, 21, 21, 42]\n", None,
),
"expected_result_inference_structural_returns_and_nested_optional_presence": (
"""
Error :: enum { failed }
exact proc(value i16) i16 { return value }
callback proc($T type) @proc(value T) T { return exact }
optional proc($T type) ?T { return 42 }
fallible proc($T, $E type) T ! E { return 42 }
identity proc($T type, value T) T { return value }
main proc() [4]i16 {
call @proc(value i16) i16 :: callback()
maybe ?i16 :: optional()
result i16 ! Error :: fallible()
nested ??i16 :: identity(some!(null))
if (nested == null or nested? != null) return [0, 0, 0, 0]
return [call(42), (maybe?), result catch 0, 42]
}
""", b"[42, 42, 42, 42]\n", None,
),
"expected_result_inference_rejects_conflicting_rigid_argument": (
"""
identity proc($T type, value T) T { return value }
main proc() u16 {
value i16 :: 42
return identity(value)
}
""", b"", b"cannot infer consistent compile-time arguments",
),
"expected_result_inference_requires_context_for_result_only_arguments": (
"""
answer proc($T type) T { return 42 }
main proc() i16 {
value :: answer()
return 42
}
""", b"", b"cannot infer consistent compile-time arguments",
),
"generic_contextual_enum_rejects_unknown_member": (
"""
Key :: enum { first }
choose proc($T type, anchor @T, value T) T { return value }
main proc() i16 { key Key :: .first
choose(&key, .missing)
return 42 }
""", b"", b"record has no such field",
),
"generic_contextual_only_call_cannot_infer_nominal_type": (
"""
choose proc($T type, value T) T { return value }
main proc() i16 { choose(.first)
return 42 }
""", b"", b"cannot infer consistent compile-time arguments",
),
"generic_contextual_arguments_do_not_hide_rigid_type_conflicts": (
"""
First :: enum { first }
Second :: enum { first }
choose proc($T type, left @T, right @T, value T) T { return value }
main proc() i16 {
left First :: .first
right Second :: .first
choose(&left, &right, .first)
return 42
}
""", b"", b"cannot infer consistent compile-time arguments",
),
"undefined_rejects_immutable_local": (
"main proc() i16 { value i16 :: undefined\nreturn value }",
b"", b"undefined requires a concrete mutable local declaration",
),
"undefined_rejects_untyped_local": (
"main proc() i16 { value := undefined\nreturn 42 }",
b"", b"undefined requires a concrete mutable local declaration",
),
"undefined_rejects_noninitializer_expression": (
"main proc() i16 { return undefined }",
b"", b"undefined requires a concrete mutable local declaration",
),
"undefined_rejects_inferred_array_length": (
"main proc() i16 { values [_]mut i16 := undefined\nreturn 42 }",
b"", b"undefined requires a concrete mutable local declaration",
),
"undefined_rejects_global_storage": (
"value i16 := undefined\nmain proc() i16 { return value }",
b"", b"undefined requires a concrete mutable local declaration",
),
"inline_match_composed_enums_keep_static_sum_tags_and_runtime_dispatch": (
"""
First :: enum { skipped, first }
Second :: enum { second, last }
Errors :: alias (First | (Second | First))
selected proc(input Errors, calls @mut i16) Errors {
calls^ = calls^ + 1
return input
}
known proc($tag Errors) i16 {
return match tag { .first: 19, .second: 23, else: 0 }
}
read proc(input Errors, calls @mut i16) i16 {
return match selected(input, calls) {
.skipped: 0,
inline |tag|: known(tag),
}
}
main proc() [2]i16 {
calls i16 := 0
total :: read(.skipped, &calls) + read(.first, &calls) + read(.second, &calls) + read(.last, &calls)
return [total, calls]
}
""", b"[42, 4]\n", None,
),
"inline_match_composed_payloads_catch_static_tags_and_owned_copies": (
"""
Missing :: enum { missing }
Detail :: union(enum) { number i8, text string, empty void }
Failure :: struct { values [2]mut i16 }
Errors :: alias ((Missing | Detail) | (Failure | Missing))
fail proc(input Errors) i16 ! Errors { return input }
exact proc(value i8) i16 { return i16(value) }
read proc(input Errors) i16 {
fail(input) catch |err| {
match err {
.missing: return 0,
inline |payload, tag|: {
match tag {
inline |selected|: {
if (selected == .number) { return exact(payload) }
else if (selected == .text) { return i16(payload.len) }
else if (selected == .Failure) {
copy := payload
copy.values[0] = 0
return payload.values[0] + payload.values[1]
} else {
payload
return 1
}
},
}
},
}
}
return -1
}
main proc() i16 {
return read(.missing) + read(.number{19}) + read(.text{"ok"}) + read(.Failure{values = [9, 11]}) + read(.empty)
}
""", b"42\n", None,
),
"inline_match_composed_type_producers_and_constant_inputs": (
"""
Missing :: enum { missing }
Detail :: union(enum) { count usize, empty void }
Failure :: struct { count usize }
Errors :: alias (Missing | Detail | (Failure | Detail))
Storage proc(input Errors) type {
length usize := 0
match input {
inline |payload, tag|: {
if (tag == .count) { length = payload }
else if (tag == .Failure) { length = payload.count }
else if (tag == .missing) { length = 1 }
else { length = 0 }
},
}
return struct { values [length]i16 }
}
score proc(input Errors) i16 {
return match input {
inline |payload, tag|: match tag { .count: i16(payload), else: 0 },
}
}
known proc($input Errors) i16 { return score(input) }
main proc() i16 {
first Storage(.count{2}) :: { values = [19, 20] }
same Storage(.count{2}) :: first
record Storage(.Failure{count = 2}) :: { values = [0, 0] }
other Storage(.missing) :: { values = [0] }
empty Storage(.empty) :: { values = [] }
return same.values[0] + same.values[1] + $(score(.count{2})) + known(.count{1}) + other.values[0] + i16(empty.values.len) + record.values[0]
}
""", b"42\n", None,
),
"inline_match_composed_payload_cleanup_on_error_return": (
"""
Missing :: enum { missing }
Detail :: union(enum) { failed i16 }
Errors :: alias (Missing | Detail)
forward proc(input Errors, cleanups @mut i16) i16 ! Errors {
match input {
inline |payload, tag|: {
defer cleanups^ = cleanups^ + 1
if (tag == .failed) { return .failed{payload} }
else { return .missing }
},
}
}
main proc() i16 {
cleanups i16 := 0
value :: forward(.failed{41}, &cleanups) catch |err| match err {
inline |payload, tag|: match tag { .failed: payload, else: 0 },
}
return value + cleanups
}
""", b"42\n", None,
),
"inline_match_composed_enums_reject_second_capture": (
"A :: enum { a }\nB :: enum { b }\nmain proc() i16 { input (A | B) :: .a\nreturn match input { inline |value, tag|: 42 } }",
b"", b"inline match arm requires one enum capture",
),
"inline_match_composed_rejects_conflicting_variant_payloads": (
"A :: union(enum) { failed i8 }\nB :: union(enum) { failed i16 }\nmain proc() i16 { input (A | B) :: .failed{42}\nreturn match input { inline |payload, tag|: i16(payload) } }",
b"", b"sum composition requires compatible",
),
"inline_match_composed_preserves_narrow_payload_type": (
"A :: enum { a }\nB :: union(enum) { failed i8 }\nread proc(input (A | B)) i16 { return match input { inline |payload, tag|: match tag { .failed: payload, else: i16(0) } } }\nmain proc() i16 { return read(.failed{42}) }",
b"", b"incompatible value type",
),
"inline_match_composed_rejects_fully_covered_arm": (
"A :: enum { a }\nB :: enum { b }\nmain proc() i16 { input (A | B) :: .a\nreturn match input { .a, .b: 42, inline |_|: 0 } }",
b"", b"match arm is unreachable",
),
"inline_match_runtime_enum_static_capture_expression_and_single_subject": (
"""
Mode :: enum(i16) { handled = -7, first = 3, second = 8, answer = 42, zero = 90 }
selected proc(value Mode, calls @mut i16) Mode {
calls^ = calls^ + 1
return value
}
remaining proc($tag Mode) i16 {
if (tag == .answer) { return 42 }
else if (tag == .zero) { return 0 }
else { return false }
}
read proc(value Mode, calls @mut i16) i16 {
return match selected(value, calls) {
.handled: 0,
.first, .second: 0,
inline |tag|: remaining(tag),
}
}
main proc() [2]i16 {
calls i16 := 0
total :: (
read(.handled, &calls) + read(.first, &calls) + read(.second, &calls)
+ read(.answer, &calls) + read(.zero, &calls)
)
return [total, calls]
}
""", b"[42, 5]\n", None,
),
"inline_match_generic_heterogeneous_payloads_static_tags_and_nested_selection": (
"""
Tag :: enum(i16) { handled = -7, first = 3, second = 8, number = 42, record = 90, text = 100, empty = 120 }
Pair :: struct { values [2]i16 }
Choice :: union(Tag) { text string, empty void, record Pair, number i8, handled bool, second bool, first bool }
narrow proc($tag Tag, value i8) i16 {
if (tag == .number) return i16(value) else return false
}
pair proc(value Pair) i16 { return value.values[0] + value.values[1] }
read proc($T type, input T) i16 {
return match input {
.handled: 0,
.first, .second: 0,
inline |payload, tag|: match tag {
.number: narrow(tag, payload),
.record: pair(payload),
.text: i16(payload.len),
.empty: 1,
else: false,
},
}
}
nested proc(input Choice) i16 {
match input {
.handled, .first, .second: return 0,
inline |payload, tag|: {
match tag {
inline |selected|: {
if (selected == .number) { return narrow(tag, payload) }
else if (selected == .record) { return pair(payload) }
else if (selected == .text) { return i16(payload.len) }
else {
payload
return 1
}
},
}
},
}
}
main proc() i16 {
if (read(Choice, .handled{false}) + read(Choice, .first{true}) + read(Choice, .second{false}) != 0) return -1
if (nested(.number{19}) + nested(.record{values = [9, 11]}) + nested(.text{"ok"}) + nested(.empty) != 42) return -2
return (
read(Choice, .number{19}) + read(Choice, .record{values = [9, 11]})
+ read(Choice, .text{"ok"}) + read(Choice, .empty)
)
}
""", b"42\n", None,
),
"inline_match_union_subject_once_and_payload_copy_isolation_without_tag": (
"""
Pair :: struct { values [2]mut i16 }
Choice :: union(enum) { record Pair, other Pair }
exact proc(value Pair) i16 { return value.values[0] + value.values[1] }
selected proc(input @Choice, calls @mut i16) Choice {
calls^ = calls^ + 1
return input^
}
main proc() i16 {
input Choice := .record{values = [19, 23]}
calls i16 := 0
match selected(&input, &calls) {
inline |payload|: {
input.record.values[0] = 0
copied := payload
copied.values[1] = 0
if (calls != 1 or input.record.values[0] != 0 or copied.values[1] != 0) return -1
return exact(payload)
},
}
}
""", b"42\n", None,
),
"inline_match_return_break_continue_run_arm_cleanup": (
"""
Mode :: enum { skip, add, stop }
finish proc(input Mode, cleanups @mut i16) i16 {
match input {
.skip, .stop: return 0,
inline |tag|: {
defer cleanups^ = cleanups^ + 1
if (tag == .add) return 19 else return false
},
}
}
main proc() i16 {
total i16 := 0
cleanups i16 := 0
for [Mode.skip, .add, .stop, .add] |input| {
match input {
inline |tag|: {
defer cleanups = cleanups + 1
if (tag == .skip) { continue }
else if (tag == .stop) { break }
else { total = total + 19 }
},
}
}
result :: finish(.add, &cleanups)
return total + result + cleanups
}
""", b"42\n", None,
),
"inline_match_rejects_scalar_subject": (
"main proc() i16 { return match i16(42) { inline |value|: value } }",
b"", b"inline match arm requires an enum or tagged union",
),
"inline_match_rejects_untagged_union_subject": (
"Choice :: union { number i16 }\nmain proc() i16 { input Choice :: { number = 42 }\nreturn match input { inline |value|: value } }",
b"", b"inline match arm requires an enum or tagged union",
),
"inline_match_rejects_second_enum_capture": (
"Mode :: enum { answer }\nmain proc() i16 { return match Mode.answer { inline |value, tag|: 42 } }",
b"", b"inline match arm requires one enum capture",
),
"inline_match_rejects_redundant_remaining_arm": (
"Mode :: enum { first, second }\nmain proc() i16 { return match Mode.first { .first, .second: 42, inline |_|: 0 } }",
b"", b"match arm is unreachable",
),
"inline_match_rejects_following_arm": (
"Mode :: enum { first, second }\nmain proc() i16 { return match Mode.first { inline |_|: 42, .second: 0 } }",
b"", b"match arm is unreachable",
),
"inline_match_rejects_arm_after_else": (
"Mode :: enum { first, second }\nmain proc() i16 { return match Mode.first { else: 42, inline |_|: 0 } }",
b"", b"match arm is unreachable",
),
"inline_match_checks_preceding_duplicate_patterns": (
"Mode :: enum { first, second }\nmain proc() i16 { return match Mode.first { .first: 42, .first: 0, inline |_|: 0 } }",
b"", b"duplicate or overlapping match pattern",
),
"inline_match_rejects_duplicate_capture_names": (
"Choice :: union(enum) { number i8 }\nmain proc() i16 { input Choice :: .number{42}\nreturn match input { inline |value, value|: 42 } }",
b"", b"duplicate name or forbidden shadowing",
),
"inline_match_rejects_shadowed_enum_capture": (
"Mode :: enum { answer }\nmain proc() i16 { value :: 42\nreturn match Mode.answer { inline |value|: 42 } }",
b"", b"duplicate name or forbidden shadowing",
),
"inline_match_rejects_shadowed_tag_capture": (
"Choice :: union(enum) { number i8 }\nmain proc() i16 { tag :: 42\ninput Choice :: .number{42}\nreturn match input { inline |value, tag|: 42 } }",
b"", b"duplicate name or forbidden shadowing",
),
"inline_match_enum_capture_is_immutable": (
"Mode :: enum { first, second }\nmain proc() i16 { match Mode.first { inline |value|: value = .second }\nreturn 42 }",
b"", b"assignment requires a mutable local binding",
),
"inline_match_payload_capture_is_immutable": (
"Choice :: union(enum) { number i8 }\nmain proc() i16 { input Choice :: .number{42}\nmatch input { inline |value|: value = 0 }\nreturn 42 }",
b"", b"assignment requires a mutable local binding",
),
"inline_match_tag_capture_is_immutable": (
"Choice :: union(enum) { number i8, empty void }\nmain proc() i16 { input Choice :: .number{42}\nmatch input { inline |value, tag|: tag = .empty }\nreturn 42 }",
b"", b"assignment requires a mutable local binding",
),
"inline_match_payload_preserves_narrow_type": (
"Choice :: union(enum) { number i8 }\nread proc(input Choice) i16 { match input { inline |value|: return value } }\nmain proc() i16 { return read(.number{42}) }",
b"", b"return does not match",
),
"inline_match_payload_is_not_a_comptime_binding": (
"Choice :: union(enum) { number i8 }\nknown proc($value i8) i16 { return i16(value) }\nread proc(input Choice) i16 { return match input { inline |value|: known(value) } }\nmain proc() i16 { return read(.number{42}) }",
b"", b"compile-time",
),
"inline_match_resolves_unselected_bodies": (
"Mode :: enum { first, second }\nmain proc() i16 { return match Mode.first { inline |tag|: match tag { .first: 42, .second: missing } } }",
b"42\n", b"unknown name",
),
"inline_match_rejects_pointer_capture_syntax": (
"Choice :: union(enum) { number i8 }\nmain proc() i16 { input Choice :: .number{42}\nreturn match input { inline |*value|: 42 } }",
b"", b"unexpected token",
),
"inline_match_nested_optional_loop_and_ordinary_match_captures": (
"""
Mode :: enum { skip, answer }
Choice :: union(enum) { mode Mode }
score proc(value Mode) i16 {
return match value { inline |tag|: match tag { .skip: 0, .answer: 14 } }
}
read proc(input ?Mode, choice Choice) i16 {
total i16 := 0
if input |value| {
total = match value { inline |tag|: score(tag) }
}
pending ?Mode := input
while pending |value| {
total = total + match value { inline |tag|: score(tag) }
pending = null
}
match choice {
.mode |value|: {
total = total + match value { inline |tag|: score(tag) }
}
}
return total
}
main proc() i16 { return read(.answer, .mode{.answer}) + read(null, .mode{.skip}) }
""", b"42\n", None,
),
"inline_match_type_producer_selects_generated_storage": (
"""
Mode :: enum { small, wide }
Storage proc(input Mode) type {
match input { inline |tag|: {
if (tag == .small) { return struct { value i8 = 19 } }
else { return struct { value i16 = 23 } }
} }
}
main proc() i16 {
small Storage(.small) :: {}
wide Storage(.wide) :: {}
return i16(small.value) + wide.value
}
""", b"42\n", None,
),
"inline_match_auto_tag_nested_expansion_infers_exact_payload_generics": (
"""
Choice :: union(enum) { number i8, empty void }
identity proc($T type, value T) T { return value }
read proc(input Choice) i16 {
match input { inline |payload, tag|: match tag {
inline |value|: {
if (value == .number) { return i16(identity(payload)) }
else {
payload
return 2
}
}
} }
}
main proc() i16 { return read(.number{40}) + read(.empty) }
""", b"42\n", None,
),
"inline_match_type_producer_updates_outer_type_and_value_locals": (
"""
Choice :: union(enum) { number u8, empty void }
Storage proc(input Choice) type {
length usize := 1
Element := i8
for [input] |item| {
match item { inline |payload, tag|: {
if (tag == .number) {
length = usize(payload)
Element = i16
} else { length = 2 }
} }
}
return struct { values [length]Element }
}
main proc() i16 {
value Storage(.number{2}) :: { values = [19, 23] }
return value.values[0] + value.values[1]
}
""", b"42\n", None,
),
"inline_for_heterogeneous_tuple_exact_captures_and_nested_values": (
"""
Choice :: union(enum) { number i8, empty void }
values proc() struct { i8, bool, string, [2]i16, Choice, ?i16 } {
return {19, true, "ok", [10, 11], .number{2}, 0}
}
narrow proc(value i8) i16 { return i16(value) }
main proc() i16 {
total i16 := 0
inline for values() |value, index| {
at usize :: index
if (at == 0) {
total = total + narrow(value)
} else if (at == 1) {
if (!value) return -1
} else if (at == 2) {
text string :: value
if (text.len != 2) return -2
} else if (at == 3) {
total = total + value[0] + value[1]
} else if (at == 4) {
match value { .number |payload|: { total = total + narrow(payload) }, .empty: {} }
} else total = total + value?
}
return total
}
""", b"42\n", None,
),
"inline_for_mixed_type_value_tuple_generates_runtime_storage": (
"""
Child :: struct { value i16 = 40 }
Metadata :: alias struct { type, usize, type, string }
metadata proc() Metadata { return {Child, 2, i16, "ok"} }
answer proc($input Metadata, bias i16) i16 {
total i16 := 0
inline for input |item, index| {
if (index == 0) {
value item :: {}
total = total + value.value
} else if (index == 1) {
values [item]i16 :: [0, bias]
total = total + values[1]
} else if (index == 2) {
value item :: total
total = value
} else if (item.len != 2) return -1
}
return total
}
main proc() i16 { return answer(metadata(), 2) }
""", b"42\n", None,
),
"inline_for_tuple_literals_empty_shapes_and_static_transfers": (
"""
main proc() i16 {
total i16 := 0
cleanups i16 := 0
inline for ({}) |_| { return false }
inline for ({i8(19), true, "stop", i16(99)}) |item, index| {
defer cleanups = cleanups + 1
if (index == 0) {
total = total + i16(item)
} else if (index == 1) {
continue
} else if (index == 2) {
break
} else total = false
total = total + 20
}
return total + cleanups
}
""", b"42\n", None,
),
"inline_for_type_producer_tuple_places_observe_updates_and_isolate_copies": (
"""
Storage proc() type {
config := {i8, usize(1), "before"}
saved :: config
length usize := 0
inline for config |item, index| {
if (index == 0) {
if (item != i8) return bool
config.0 = i16
config.1 = 2
config.2 = "after"
} else if (index == 1) {
length = item
} else if (item.len != 5) return bool
}
if (saved.0 != i8 or saved.1 != 1 or (saved.2).len != 6) return bool
Element :: config.0
return struct { values [length]Element }
}
main proc() i16 {
value Storage() :: { values = [19, 23] }
return value.values[0] + value.values[1]
}
""", b"42\n", None,
),
"inline_for_nested_tuple_projections_and_aggregate_copy_isolation": (
"""
Item :: struct { values [2]mut i16 }
tuples proc() struct { struct { Item, bool }, string } {
return {{Item { values = [19, 23] }, true}, "ok"}
}
main proc() i16 {
input :: tuples()
total i16 := 0
inline for input.0 |item, index| {
if (index == 0) {
copy := item
copy.values[0] = 0
total = item.values[0] + item.values[1]
} else if (!item) return -1
}
return total
}
""", b"42\n", None,
),
"inline_for_tuple_rejects_runtime_dependency_even_with_discard_capture": (
"""
walk proc(value i16) i16 {
inline for ({i8(1), value}) |_| { break }
return 42
}
main proc() i16 { return walk(42) }
""", b"", b"compile-time",
),
"inline_for_tuple_rejects_named_records": (
"""
main proc() i16 {
inline for ({number = i16(42)}) |value| { return value }
return 0
}
""", b"", b"for-loop iteration requires",
),
"inline_for_tuple_capture_is_immutable": (
"""
main proc() i16 {
inline for ({i8(1), true}) |value, index| {
if (index == 0) value = 42
}
return 0
}
""", b"", b"assignment requires a mutable local binding",
),
"inline_for_tuple_preserves_narrow_overflow": (
"""
main proc() i16 {
inline for ({i8(127), true}) |value, index| {
if (index == 0) next :: value + 1
}
return 42
}
""", b"", b"integer arithmetic overflow",
),
"inline_for_tuple_rejects_storage_escape_before_break": (
"""
values proc() struct { i16, @i16 } {
local i16 :: 2
return {42, &local}
}
main proc() i16 {
inline for values() |_| { break }
return 42
}
""", b"", b"escape",
),
"ordinary_for_still_rejects_heterogeneous_tuple": (
"""
main proc() i16 {
for ({i16(42), true}) |_| {}
return 42
}
""", b"", b"for-loop iteration requires",
),
"inline_for_range_runtime_calls_and_constant_branches": (
"""
add proc(value i16, bias i16) i16 { return value + bias }
answer proc(bias i16) i16 {
total i16 := 0
inline for (i8(0)..i8(3)) |index| {
if (index == 0) {
total = add(total, bias)
} else {
total = add(total, i16(index))
}
if (index > 9) return false
}
return total
}
main proc() i16 { return answer(39) }
""", b"42\n", None,
),
"inline_for_inferred_arrays_concretize_scalar_shorthand": (
"""
signed proc(value i64) i64 { return value }
real proc(value f64) f64 { return value }
integer proc() int { return 23 }
floating proc() float { return 22.5 }
main proc() i64 {
total i64 := 0
inline for [int(19), integer()] |value| { total = total + signed(value) }
fraction f64 := 0.0
inline for [float(19.5), floating()] |value| { fraction = fraction + real(value) }
return total + i64(fraction) - 42
}
""", b"42\n", None,
),
"inline_for_array_constants_and_usize_indices": (
"""
data proc() [2]i16 { return [19, 22] }
at proc(index usize, value i16) i16 { return value + i16(index) }
main proc() i16 {
total i16 := 0
inline for data() |value, index| {
if (value == 19) {
total = total + at(index, value)
} else if (value == 22) {
total = total + at(index, value)
} else return false
}
return total
}
""", b"42\n", None,
),
"inline_for_string_bytes_embedded_nul_and_usize_indices": (
r"""
text proc() string { return "a\0b" }
at proc(index usize, byte u8) i16 {
if (byte == 0) return i16(index) + 39
return 1
}
main proc() i16 {
total i16 := 0
inline for text() |byte, index| {
if (index == 1) {
if (byte != 0) return false
} else if (byte == 0) return false
total = total + at(index, byte)
}
return total
}
""", b"42\n", None,
),
"inline_for_type_array_specializes_each_runtime_body": (
"""
types proc() [2]type { return [i16, bool] }
add proc(value i16) i16 { return value + 1 }
main proc() i16 {
total i16 := 0
inline for types() |T, index| {
if (T == i16) {
value T :: 39
total = total + add(value)
} else {
value T :: true
if (value) total = total + i16(index) + 1
}
}
return total
}
""", b"42\n", None,
),
"inline_for_narrow_signed_and_unsigned_inclusive_maxima": (
"""
signed proc(value i8) i16 { return i16(value) }
unsigned proc(value u8) i16 { return i16(value) }
main proc() [3]i16 {
negative i16 := 0
inline for (i8(-2)..i8(0)) |value| { negative = negative + signed(value) }
high i16 := 0
inline for (i8(126)..=i8(127)) |value| { high = high + signed(value) }
top i16 := 0
inline for (u8(254)..=u8(255)) |value| { top = top + unsigned(value) }
return [negative, high, top]
}
""", b"[-3, 253, 509]\n", None,
),
"inline_for_nested_inline_and_ordinary_loops": (
"""
answer proc(length usize) i16 {
total i16 := 0
inline for [i16(10), i16(11)] |base| {
inline for (i8(0)..i8(2)) |offset| {
if (offset == 0) continue
for (0..length) |index| {
if (index == 0) continue
total = total + base
break
}
}
}
return total
}
main proc() i16 { return answer(3) + answer(2) }
""", b"42\n", None,
),
"inline_for_static_break_continue_run_iteration_defers": (
"""
walk proc(cleanups @mut i16) i16 {
total i16 := 0
inline for (i8(0)..i8(5)) |index| {
defer cleanups^ = cleanups^ + 1
if (index < 1) continue
if (index == 3) break
total = total + i16(index)
}
return total
}
main proc() i16 {
cleanups i16 := 0
total :: walk(&cleanups)
return total + cleanups + 35
}
""", b"42\n", None,
),
"inline_for_static_transfers_skip_invalid_tail_and_later_iterations": (
"""
main proc() i16 {
inline for (i8(0)..i8(3)) |index| {
if (index == 0) continue
if (index == 1) break
return false
}
return 42
}
""", b"42\n", None,
),
"inline_for_tagged_match_transfers_prune_tail_and_payloads": (
"""
Choice :: union(enum) { number i16, stop void }
choices proc() [4]Choice { return [.number{0}, .number{39}, .stop, .number{99}] }
main proc() i16 {
total i16 := 0
inline for choices() |choice| {
defer total = total + 1
match choice {
.number |value|: {
if (value == 0) continue
total = total + value
continue
},
.stop: break,
}
return false
}
return total
}
""", b"42\n", None,
),
"inline_for_rejects_runtime_break": (
"""
walk proc(stop bool) i16 {
inline for (i8(0)..i8(2)) |_| {
if (stop) break
}
return 42
}
main proc() i16 { return walk(true) }
""", b"", b"compile-time-resolvable",
),
"inline_for_rejects_runtime_continue": (
"""
walk proc(skip bool) i16 {
inline for [i16(1), i16(2)] |_| {
if (skip) continue
}
return 42
}
main proc() i16 { return walk(true) }
""", b"", b"compile-time-resolvable",
),
"inline_for_runtime_return_runs_iteration_defer": (
"""
find proc(take bool, cleanups @mut i16) i16 {
inline for [i16(1), i16(2), i16(3)] |value| {
defer cleanups^ = cleanups^ + 1
if (take and value == 2) return 40
}
return 0
}
main proc() i16 {
cleanups i16 := 0
value :: find(true, &cleanups)
return value + cleanups
}
""", b"42\n", None,
),
"inline_for_runtime_error_return_runs_errdefer_only_on_error": (
"""
Error :: enum { failed }
walk proc(fail bool, cleanups @mut i16) i16 ! Error {
inline for (i8(0)..i8(3)) |index| {
defer cleanups^ = cleanups^ + 1
errdefer cleanups^ = cleanups^ + 10
if (fail and index == 1) return .failed
}
return 39
}
main proc() [2]i16 {
failed i16 := 0
success i16 := 0
left :: walk(true, &failed) catch 30
right :: walk(false, &success) catch 0
return [left + failed, right + success]
}
""", b"[42, 42]\n", None,
),
"inline_for_empty_ranges_arrays_strings_skip_invalid_typing": (
"""
empty proc() [0]type { return [] }
main proc() i16 {
inline for (i8(2)..i8(-2)) |_| { return false }
inline for (i8(1)..i8(1)) |_| { return i8(128) }
inline for empty() |_| { return false }
inline for "" |_| { return i8(128) }
return 42
}
""", b"42\n", None,
),
"inline_for_capture_keeps_narrow_arithmetic_overflow": (
"""
main proc() i16 {
inline for (i8(127)..=i8(127)) |value| { next :: value + 1 }
return 42
}
""", b"", b"integer arithmetic overflow",
),
"inline_for_capture_is_immutable": (
"""
main proc() i16 {
inline for [i16(1)] |value| { value = 42 }
return 0
}
""", b"", b"assignment requires a mutable local binding",
),
"inline_for_index_is_immutable": (
"""
main proc() i16 {
inline for "a" |_, index| { index = 42 }
return 0
}
""", b"", b"assignment requires a mutable local binding",
),
"inline_for_rejects_runtime_range_bound": (
"""
walk proc(length usize) i16 {
inline for (0..length) |_| {}
return 42
}
main proc() i16 { return walk(2) }
""", b"", b"compile-time value",
),
"inline_for_rejects_runtime_array": (
"""
walk proc(values [2]i16) i16 {
inline for values |_| {}
return 42
}
main proc() i16 { return walk([19, 23]) }
""", b"", b"compile-time value",
),
"inline_for_rejects_runtime_string": (
"""
walk proc(text string) i16 {
inline for text |_| {}
return 42
}
main proc() i16 { return walk("ok") }
""", b"", b"compile-time value",
),
"inline_for_rejects_pointer_capture": (
"""
main proc() i16 {
inline for [i16(42)] |@value| { return value^ }
return 0
}
""", b"", b"escape",
),
"inline_for_materializes_readonly_byte_slice_elements": (
"""
data proc() [1][]u8 { return ["borrowed"] }
main proc() usize {
inline for data() |value| { return value.len }
return 0
}
""", b"8\n", None,
),
"inline_for_rejects_mutable_byte_slice_element_escape": (
"""
data proc() [1][]mut u8 {
values [1]mut u8 := [42]
return [values[..]]
}
main proc() usize {
inline for data() |value| { return value.len }
return 0
}
""", b"", b"escape",
),
"inline_for_expansion_is_bounded": (
"""
main proc() i16 {
inline for (0..usize(100000)) |_| {}
return 42
}
""", b"", b"step limit",
),
"struct_type_literal_fields_contextual_defaults_and_required_null": (
"""
present proc() ??i16 { return 2 }
Record :: struct_type!(
.auto,
{"number", "ready", "text", "maybe", "required"},
{i16, bool, string, ?i16, ?i16},
{null, true, "ok", present(), null},
)
main proc() i16 {
value Record :: { number = 40, required = 2 }
if (!value.ready or value.text.len != 2) return -1
if (value.maybe? != 2) return -2
return value.number + value.required?
}
""", b"42\n", None,
),
"struct_type_computed_arrays_snapshots_and_nominal_cache_identity": (
"""
names proc() [2]mut string {
result [2]mut string := ["", ""]
result[0] = "value"
result[1] = "bias"
return result
}
change proc(input [2]mut type, T type) [2]mut type {
copied := input
copied[0] = T
return copied
}
Generated proc(T type, bias i16) type {
fields := names()
types [2]mut type := undefined
types[0] = i8
types[1] = i16
changed := change(types, T)
if (types[0] != i8 or changed[0] != T) return bool
defaults [2]mut ?i16 := undefined
defaults[0] = null
defaults[1] = bias
Result :: struct_type!(.auto, fields, changed, defaults)
fields[0] = "replaced"
types[1] = bool
changed[0] = bool
defaults[1] = 0
return Result
}
Other proc() type {
return struct_type!(.auto, ["value", "bias"], [i16, i16], [null, 2])
}
Selected :: alias Generated(i16, 2)
main proc() i16 {
if (Selected != Generated(i16, 2)) return -1
if (Selected == Generated(i16, 3) or Selected == Other()) return -2
value Selected :: { value = 40 }
same Generated(i16, 2) :: value
return same.value + same.bias
}
""", b"42\n", None,
),
"struct_type_tuple_helper_nested_aggregate_defaults_and_copy_isolation": (
"""
Child :: struct { values [2]mut i8, maybe ?i8 = null }
names proc() struct { string, string } { return {"rows", "bias"} }
Generated proc() type {
return struct_type!(
.auto,
names(),
[[2]mut Child, i8],
[[{ values = [19, 0] }, { values = [0, 23], maybe = 2 }], 127],
)
}
copy proc(value Generated()) Generated() { return value }
main proc() i16 {
first Generated() := {}
saved :: copy(first)
first.rows[0].values[0] = 0
first.rows[1].maybe = null
second Generated() :: {}
if (saved.rows[1].maybe? != 2 or second.bias != 127) return -1
return i16(saved.rows[0].values[0]) + i16(second.rows[1].values[1])
}
""", b"42\n", None,
),
"struct_type_empty_auto_and_nested_c_layout": (
"""
Layout :: enum { auto, c }
Tag :: enum(u8) { ready = 7 }
Empty :: struct_type!(.auto, [], [], [])
Inner :: struct_type!(.c, ["value"], [i16], [null])
Packet :: struct_type!(
Layout.c,
{"tag", "items", "pointer", "maybe"},
{Tag, [2]Inner, @i16, ?@i16},
{.ready, null, null, null},
)
identity proc(value Empty) Empty { return value }
main proc() i16 {
empty Empty :: identity({})
if (sizeof!(Packet) != 24 or alignof!(Packet) != 8) return -3
extra i16 :: 2
packet Packet :: {
items = [{ value = 19 }, { value = 21 }],
pointer = &extra,
maybe = null,
}
if (packet.tag != .ready) return -1
if packet.maybe |_| return -2
return packet.items[0].value + packet.items[1].value + packet.pointer^
}
""", b"42\n", None,
),
"struct_type_required_optional_is_not_a_null_default": (
"""
Record :: struct_type!(.auto, ["required"], [?i16], [null])
main proc() i16 {
value Record :: {}
return 42
}
""", b"", b"missing a required field",
),
"struct_type_default_preserves_narrow_field_arithmetic": (
"""
Record :: struct_type!(.auto, ["value"], [i8], [127])
main proc() i16 {
value Record := {}
value.value = value.value + 1
return i16(value.value)
}
""", b"", b"integer arithmetic overflow",
),
"struct_type_runtime_dependencies_are_not_captured": (
"""
read proc(value i16) i16 {
Record :: struct_type!(.auto, ["value"], [i16], [value])
result Record :: {}
return result.value
}
main proc() i16 { return read(42) }
""", b"", b"compile-time value",
),
"struct_type_incomplete_array_snapshot_stays_incomplete": (
"""
Generated proc() type {
types [2]mut type := undefined
types[0] = i16
saved :: types
types[1] = i16
return struct_type!(.auto, ["first", "second"], saved, [null, null])
}
main proc() i16 {
value Generated() :: { first = 19, second = 23 }
return value.first + value.second
}
""", b"", b"initialization",
),
"type_records_local_schema_defaults_and_owned_copies": (
"""
Storage proc() type {
Config :: struct { child type = i8, count usize = 2, text string = "ok" }
config Config := {}
original :: config
field!(config, "child") = i16
config.count = config.count + 1
config.text = "owned"
if (original.child != i8 or original.count != 2 or original.text.len != 2) return bool
return struct { values [config.count]config.child, bias original.child = 2 }
}
main proc() i16 {
value Storage() :: { values = [19, 21, 0] }
same Storage() :: value
return same.values[0] + same.values[1] + i16(same.bias)
}
""", b"42\n", None,
),
"type_records_nested_arrays_borrowed_iteration_and_capture_copies": (
"""
Storage proc() type {
Item :: struct { child type, values [1]mut usize }
config struct { items [2]mut Item, bias struct { value i16 } } := {
items = [{ child = i8, values = [1] }, { child = bool, values = [1] }],
bias = { value = 0 },
}
original :: config
for config.items |item, index| {
config.items[1].child = i16
config.items[index].values[0] = index + 1
config.bias.value = config.bias.value + 1
if (index == 0 and item.child != i8) return bool
if (index == 1 and item.child != i16) return bool
copied := item
copied.child = u8
if (item.child == u8) return bool
}
if (original.items[1].child != bool or original.items[1].values[0] != 1) return bool
return struct { values [config.items[1].values[0]]config.items[1].child, bias i16 = config.bias.value }
}
main proc() i16 {
value Storage() :: { values = [19, 21] }
return value.values[0] + value.values[1] + value.bias
}
""", b"42\n", None,
),
"type_records_inferred_tuples_nested_replacement_and_nominal_leaves": (
"""
Storage proc() type {
Child :: struct { value i16 }
config := { nested = { child = Child, count = usize(1) }, tuple = {i8, usize(2)} }
saved :: config
config.nested = saved.nested
config.tuple.0 = i16
config.nested.count = config.tuple.1
if (saved.tuple.0 != i8 or config.nested.child != Child) return bool
Element :: field!(config.tuple, "0")
return struct { first config.nested.child, second Child, bias Element = 2 }
}
main proc() i16 {
value Storage() :: { first = { value = 19 }, second = { value = 21 } }
copied := value.first
copied = value.second
return value.first.value + copied.value + value.bias
}
""", b"42\n", None,
),
"type_record_procedure_owned_results_inputs_and_cache_identity": (
"""
Config :: struct { child type, counts [2]mut usize, bias i16 = 2 }
config proc() Config { return { child = i16, counts = [1, 2] } }
change proc(input Config) Config {
copied := input
copied.child = u8
copied.counts[1] = 3
return copied
}
Storage proc(input Config) type {
saved :: input
changed :: change(input)
if (input.child != i16 or saved.counts[1] != 2) return bool
if (changed.child != u8 or changed.counts[1] != 3) return bool
return struct { values [input.counts[1]]input.child, bias i16 = input.bias }
}
Selected :: alias Storage(config())
main proc() i16 {
value Selected :: { values = [19, 21] }
same Storage({ child = i16, counts = [1, 2] }) :: value
return same.values[0] + same.values[1] + same.bias
}
""", b"42\n", None,
),
"type_record_procedure_nested_array_snapshots_and_nominal_leaves": (
"""
Item :: struct { child type, counts [1]mut usize }
Config :: struct { items [2]mut Item }
config proc() Config {
Child :: struct { value i16 }
return { items = [{ child = Child, counts = [1] }, { child = Child, counts = [2] }] }
}
change proc(input Config) Config {
copied := input
copied.items[0].child = u8
copied.items[1].counts[0] = 3
return copied
}
Storage proc(input Config) type {
changed :: change(input)
if (input.items[0].child != input.items[1].child) return bool
if (input.items[0].child == changed.items[0].child) return bool
if (input.items[1].counts[0] != 2 or changed.items[1].counts[0] != 3) return bool
return struct { first input.items[0].child, second input.items[1].child }
}
main proc() i16 {
value Storage(config()) :: { first = { value = 19 }, second = { value = 23 } }
same Storage(config()) :: value
copied := same.first
copied = same.second
return same.first.value + copied.value
}
""", b"42\n", None,
),
"type_record_procedure_tuple_results_and_erased_runtime_inputs": (
"""
Pair :: struct { type, usize }
pair proc() Pair { return {i16, 2} }
copy proc(input Pair) Pair { return input }
Element proc(input Pair) type { return field!(input, "0") }
add proc($input Pair, value Element(input)) Element(input) {
return value + i16(field!(input, "1"))
}
forward proc(value i16) i16 { return add(copy(pair()), value) }
main proc() i16 {
if (add({i16, usize(1)}, 40) != 41) return 0
return forward(40)
}
""", b"42\n", None,
),
"type_record_procedure_dependent_annotations_and_erased_cache_values": (
"""
config proc($T type, value T) struct { child type, bias T, detail struct { bias T } } {
return { child = T, bias = value, detail = { bias = value } }
}
Storage proc($T type, input struct { child type, bias T, detail struct { bias T } }) type {
return struct { value input.child, bias T = input.detail.bias }
}
add proc($input struct { child type, bias i16, detail struct { bias i16 } }, value input.child) input.child {
return value + input.detail.bias
}
main proc() i16 {
value Storage(i16, config(i16, 2)) :: { value = 40 }
same Storage(i16, { child = i16, bias = 2, detail = { bias = 2 } }) :: value
if (add(config(i16, 1), same.value) != 41) return 0
return add(config(i16, 2), same.value)
}
""", b"42\n", None,
),
"type_record_procedure_result_rejects_unknown_field": (
"""
config proc() struct { child type } { return { child = i16, missing = 1 } }
main proc() config().child { return 42 }
""", b"", b"no such field",
),
"type_record_procedure_result_rejects_duplicate_field": (
"""
config proc() struct { child type } { return { child = i16, child = i8 } }
main proc() config().child { return 42 }
""", b"", b"more than once",
),
"type_record_procedure_argument_rejects_missing_field": (
"""
Selected proc(input struct { child type, count usize }) type { return input.child }
main proc() Selected({ child = i16 }) { return 42 }
""", b"", b"missing a required field",
),
"type_record_procedure_result_rejects_non_type_leaf": (
"""
config proc() struct { child type } { return { child = 42 } }
main proc() config().child { return 42 }
""", b"", b"incompatible value type",
),
"type_record_procedure_argument_rejects_exact_value_leaf_mismatch": (
"""
Selected proc(input struct { child type, count usize }) type { return input.child }
Bad proc() type {
wrong u8 :: 2
return Selected({ child = i16, count = wrong })
}
main proc() Bad() { return 42 }
""", b"", b"incompatible value type",
),
"type_record_procedure_erased_argument_rejects_exact_type_leaf_mismatch": (
"""
add proc($input struct { child type }, value input.child) input.child { return value }
main proc() i16 {
wrong u8 :: 42
return add({ child = i16 }, wrong)
}
""", b"", b"incompatible value type",
),
"type_record_procedure_result_preserves_value_leaf_overflow": (
"""
config proc() struct { child type, count i8 } { return { child = i16, count = 128 } }
main proc() config().child { return 42 }
""", b"", b"outside its runtime type",
),
"type_record_procedure_rejects_runtime_dependency": (
"""
config proc(wide bool) struct { child type } {
if (wide) return { child = i16 }
return { child = i8 }
}
read proc(wide bool) i16 {
value config(wide).child :: 42
return i16(value)
}
main proc() i16 { return read(true) }
""", b"", b"generic argument must be a compile-time value",
),
"type_record_procedure_nested_execution_shares_step_limit": (
"""
config proc(count usize) struct { child type } {
for (0..count) |_| { }
return { child = i16 }
}
Selected proc() type {
for (0..usize(100)) |index| { input :: config(index + 100) }
return i16
}
main proc() Selected() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"type_record_procedure_results_do_not_enable_runtime_storage": (
"""
config proc() struct { child type, count i16 } { return { child = i16, count = 42 } }
main proc() i16 {
input :: config()
return input.count
}
""", b"", b"",
),
"type_records_reject_unknown_initializer_field": (
"""
Bad proc() type {
config struct { child type } :: { child = i16, missing = 1 }
return config.child
}
main proc() Bad() { return 42 }
""", b"", b"no such field",
),
"type_records_reject_duplicate_initializer_field": (
"""
Bad proc() type {
config struct { child type } :: { child = i16, child = i8 }
return config.child
}
main proc() Bad() { return 42 }
""", b"", b"more than once",
),
"type_records_reject_missing_initializer_field": (
"""
Bad proc() type {
config struct { child type, count usize } :: { child = i16 }
return config.child
}
main proc() Bad() { return 42 }
""", b"", b"missing a required field",
),
"type_records_reject_non_type_leaf": (
"""
Bad proc() type {
config struct { child type } :: { child = 42 }
return config.child
}
main proc() Bad() { return 42 }
""", b"", b"incompatible value type",
),
"type_records_preserve_value_leaf_overflow": (
"""
Bad proc() type {
config struct { child type, count i8 } := { child = i16, count = 127 }
config.count = config.count + 1
return config.child
}
main proc() Bad() { return 42 }
""", b"", b"integer arithmetic overflow",
),
"type_records_reject_immutable_capture_updates": (
"""
Bad proc() type {
for [{ child = i16 }] |item| { item.child = i8 }
return i16
}
main proc() Bad() { return 42 }
""", b"", b"writable array element",
),
"type_records_reject_readonly_nested_array_updates": (
"""
Bad proc() type {
config struct { children [1]type } := { children = [i16] }
config.children[0] = i8
return i16
}
main proc() Bad() { return 42 }
""", b"", b"writable array element",
),
"type_records_reject_unknown_selected_field": (
"""
Bad proc() type {
config :: { child = i16 }
return field!(config, "missing")
}
main proc() Bad() { return 42 }
""", b"", b"no such field",
),
"type_records_reject_unused_invalid_value_field": (
"""
Bad proc() type {
Config :: struct { child type, invalid void }
return i16
}
main proc() Bad() { return 42 }
""", b"42\n", b"void cannot be stored",
),
"type_records_reject_unused_invalid_default": (
"""
Bad proc() type {
Config :: struct { child type, count i8 = 128 }
return i16
}
main proc() Bad() { return 42 }
""", b"", b"outside its runtime type",
),
"type_records_do_not_enable_runtime_storage": (
"""
main proc() i16 {
config :: { child = i16, count = 42 }
return config.count
}
""", b"", b"type name cannot be used as a value",
),
"field_reflection_runtime_places_callbacks_and_single_evaluation": (
"""
Point :: struct { value i16, callback @proc(value i16) i16 }
add proc(value i16) i16 { return value + 2 }
place proc(point @mut Point, calls @mut i16) @mut Point {
calls^ = calls^ + 1
return point
}
name proc() string { return "val\\x75e" }
main proc() [3]i16 {
point Point := { value = 19, callback = add }
calls i16 := 0
field!(place(&point, &calls), name()) = 40
pointer @mut i16 :: &field!(point, "value")
pointer^ = pointer^ + 1
return [field!(point, "callback")(field!(point, "value")), calls, point.value]
}
""", b"[43, 1, 41]\n", None,
),
"field_reflection_tuple_enum_union_and_sequence_members": (
"""
A :: enum { first, second }
B :: enum { third }
E :: alias A | B
Choice :: union(enum) { payload i16, empty void }
read proc($name string, value struct { count i16 }) i16 {
return field!(value, name)
}
main proc() [4]i16 {
tuple :: {i16(19), i16(21)}
choice Choice :: { payload = 2 }
values [2]i16 :: [19, 21]
member E :: field!(E, "third")
if (member != E.third) return [0, 0, 0, 0]
return [
field!(tuple, "0") + field!(tuple, "1") + field!(choice, "payload"),
i16(field!(values, "len")),
field!(&values, "ptr")[1],
read("count", { count = 42 }),
]
}
""", b"[42, 2, 21, 42]\n", None,
),
"field_reflection_type_control_and_constant_materialization": (
"""
Config :: struct { count usize, value i16 }
config proc() Config { return { count = 2, value = 21 } }
Storage proc(name string) type {
settings :: config()
types :: [i16, bool]
return struct {
values [field!(settings, name)]types[0]
bias i16 = i16(field!(types, "len"))
}
}
main proc() i16 {
value Storage("count") :: { values = [19, 21] }
constant :: $(field!(config(), "value"))
return value.values[0] + constant + value.bias
}
""", b"42\n", None,
),
"field_reflection_type_control_updates_names_and_nested_places": (
"""
Selected proc() type {
config struct { left [1]mut usize, right [1]mut usize } := { left = [0], right = [0] }
original :: config
for ["left", "right"] |name| { field!(config, name)[0] = 2 }
if (original.left[0] != 0 or original.right[0] != 0) return bool
return [config.left[0] + config.right[0]]i16
}
main proc() i16 {
values Selected() :: [10, 10, 10, 12]
return values[0] + values[1] + values[2] + values[3]
}
""", b"42\n", None,
),
"field_reflection_preserves_readonly_pointer_assignment": (
"""
Point :: struct { value i16 }
update proc(point @Point) void { field!(point, "value") = 0 }
main proc() i16 {
point Point :: { value = 42 }
update(&point)
return point.value
}
""", b"", b"mutable pointee",
),
"field_reflection_rejects_nonstring_names": (
"""
main proc() i16 { return field!({ value = i16(42) }, 0) }
""", b"", b"compile-time value",
),
"field_reflection_rejects_unknown_enum_members": (
"""
E :: enum { first }
main proc() E { return field!(E, "missing") }
""", b"", b"no such field",
),
"field_reflection_rejects_overflowing_tuple_ordinals": (
"""
main proc() i16 { return field!({i16(42)}, "18446744073709551616") }
""", b"", b"no such field",
),
"field_reflection_rejects_runtime_names": (
"""
read proc(name string, value struct { count i16 }) i16 {
return field!(value, name)
}
main proc() i16 { return read("count", { count = 42 }) }
""", b"", b"compile-time value",
),
"field_reflection_rejects_unknown_fields": (
"""
main proc() i16 { return field!({ count = i16(42) }, "missing") }
""", b"", b"no such field",
),
"field_reflection_rejects_noncanonical_tuple_names": (
"""
main proc() i16 { return field!({i16(42)}, "00") }
""", b"", b"no such field",
),
"field_reflection_rejects_wrong_arity": (
"""
main proc() i16 { return field!(42) }
""", b"", b"argument count",
),
"field_reflection_preserves_union_active_field_checks": (
"""
Choice :: union(enum) { value i16, empty void }
main proc() i16 {
choice Choice :: .empty
return field!(choice, "value")
}
""", b"", b"not active",
),
"collection_iteration_borrows_array_and_reads_each_element": (
"""
main proc() [2]i16 {
values [3]mut i16 := [19, 1, 100]
total i16 := 0
for values |value, index| {
if (index == 0) values[1] = 22
if (index == 2) break
total = total + value + i16(index)
continue
}
return [total, values[1]]
}
""", b"[42, 22]\n", None,
),
"collection_iteration_pointer_captures_slices_and_array_pointers": (
"""
main proc() [3]i16 {
values [2]mut i16 := [19, 21]
for (&values) |@value, index| { value^ = value^ + i16(index) }
view []mut i16 :: values[..]
for view |@value| { value^ = value^ + 1 }
total i16 := 0
for view |value| { total = total + value }
return [total - 1, values[0], values[1]]
}
""", b"[42, 20, 23]\n", None,
),
"collection_iteration_evaluates_entry_once_and_retains_slice_bound": (
"""
data proc(calls @mut i16) [2]i16 {
calls^ = calls^ + 1
return [19, 22]
}
main proc() [3]i16 {
calls i16 := 0
total i16 := 0
for data(&calls) |value, index| { total = total + value + i16(index) }
values [2]mut i16 := [20, 22]
view []mut i16 := values[..]
sum i16 := 0
for view |value| {
view = values[0..0]
sum = sum + value
}
return [total, calls, sum]
}
""", b"[42, 1, 42]\n", None,
),
"collection_iteration_aggregate_copies_nested_and_zero_cell_shapes": (
"""
Empty :: struct {}
Item :: struct { values [2]mut i16 }
main proc() [3]i16 {
items [2]mut Item := [{ values = [19, 21] }, { values = [0, 0] }]
total i16 := 0
for items |item, index| {
copied := item
copied.values[0] = copied.values[0] + 1
for copied.values |value| { total = total + value }
if (index == 0) items[1].values[1] = 0
}
empty [0]i16 :: []
for empty |_| { return [-1, -1, -1] }
cells [2]Empty :: [{}, {}]
count i16 := 0
for cells |cell, index| {
saved Empty :: cell
count = count + i16(index) + 1
}
return [total, items[0].values[0], count]
}
""", b"[42, 19, 3]\n", None,
),
"collection_iteration_strings_and_cleanup_on_transfers": (
"""
main proc() [2]i16 {
values [3]i16 :: [20, 22, 99]
total i16 := 0
cleanups i16 := 0
for values |value, index| {
defer cleanups = cleanups + 1
if (index == 2) break
total = total + value
continue
}
for "a\\0b" |byte, index| {
if (index == 1 and byte != 0) return [-1, -1]
if (index == 2 and byte != u8(98)) return [-2, -2]
}
return [total, cleanups]
}
""", b"[42, 3]\n", None,
),
"collection_iteration_ordinary_constant_procedure": (
"""
compute proc() i16 {
values [2]mut i16 := [19, 21]
view []mut i16 :: values[..]
for view |@value| { value^ = value^ + 1 }
total i16 := 0
for values |value| { total = total + value }
return total
}
main proc() i16 { return $(compute()) }
""", b"42\n", None,
),
"type_execution_collection_iteration_observes_updates_and_freezes_places": (
"""
Storage proc() type {
rows [2]mut [2]mut usize := [[1, 1], [9, 9]]
selected usize := 0
length usize := 0
for rows[selected] |value, index| {
selected = 1
(rows[0])[1] = 2
length = length + value
if (index == 0) continue
break
}
Result := i8
for "a\\0b" |byte, index| {
if (byte == 0 and index == 1) Result = i16
}
return struct { values [length]Result }
}
main proc() i16 {
value Storage() :: { values = [19, 21, 2] }
same Storage() :: value
return same.values[0] + same.values[1] + same.values[2]
}
""", b"42\n", None,
),
"type_execution_collection_nested_aggregate_captures_and_empty_body": (
"""
Storage proc() type {
items [2]struct { values [2]usize, text string } :: [
{ values = [1, 0], text = "a" }, { values = [0, 1], text = "b" },
]
length usize := 0
for items |item| {
for item.values |value| { length = length + value }
}
empty [0]i16 :: []
for empty |_| { return i8(128) }
for items |@_, index| { if (index == 1) break }
return [length]i16
}
main proc() i16 {
values Storage() :: [20, 22]
return values[0] + values[1]
}
""", b"42\n", None,
),
"collection_iteration_rejects_scalar_iterable": (
"main proc() i16 { for 1.5 |_| { return 0 }\nreturn 42 }",
b"", b"for-loop iteration requires",
),
"collection_iteration_rejects_capture_rebinding": (
"main proc() i16 { values [1]i16 :: [1]\nfor values |value| { value = 42 }\nreturn 0 }",
b"", b"assignment requires a mutable local binding",
),
"collection_iteration_rejects_index_rebinding": (
"main proc() usize { values [1]i16 :: [1]\nfor values |_, index| { index = 42 }\nreturn 0 }",
b"", b"assignment requires a mutable local binding",
),
"collection_iteration_rejects_readonly_array_pointer_mutation": (
"main proc() i16 { values [1]mut i16 :: [1]\nfor values |@value| { value^ = 42 }\nreturn 0 }",
b"", b"mutable pointee",
),
"collection_iteration_rejects_readonly_slice_pointer_mutation": (
"main proc() i16 { values [1]mut i16 := [1]\nview []i16 :: values[..]\nfor view |@value| { value^ = 42 }\nreturn 0 }",
b"", b"mutable pointee",
),
"type_execution_collection_iteration_preserves_element_type": (
"""
Bad proc() type {
values [1]i8 :: [127]
for values |value| { next :: value + 1 }
return i16
}
main proc() Bad() { return 0 }
""", b"", b"integer arithmetic overflow",
),
"type_execution_collection_iteration_preserves_step_bound": (
"""
Bad proc() type {
cells [1]i16 :: [0]
for cells |_| { while (true) {} }
return i16
}
main proc() Bad() { return 0 }
""", b"", b"compile-time execution",
),
"type_execution_aggregate_updates_preserve_copies_and_generate_defaults": (
"""
Config :: struct { values [2]mut i16, count usize, text string }
Storage proc() type {
config Config := { values = [17, 19], count = 0, text = "old" }
original :: config
for (usize(0)..2) |index| {
config.values[index] = config.values[index] + 1
config.count = config.count + 1
}
config.text = "owned"
config.values[config.count - 1] = match true {
true: config.values[0] + 4,
false: i8(128),
}
return struct {
values [config.count]mut i16 = config.values
bias i16 = original.values[0] - 17 + i16(config.text.len) - 3
}
}
main proc() i16 {
value Storage() :: {}
same Storage() :: value
return same.values[0] + same.values[1] + same.bias
}
""", b"42\n", None,
),
"type_execution_nested_array_record_updates_and_loop_transfers": (
"""
Item :: struct { length usize, value i16 }
Storage proc() type {
items [2]mut Item := [{ length = 0, value = 0 }, { length = 0, value = 0 }]
index usize := 0
while (index < 3) {
if (index == 2) break
items[index].length = index + 1
items[index].value = i16(index) + 20
index = index + 1
continue
}
return struct {
values [items[1].length]i16
bias i16 = items[0].value + items[1].value + i16(items[0].length)
}
}
main proc() i16 {
value Storage() :: { values = [0, 0] }
return value.bias
}
""", b"42\n", None,
),
"type_execution_field_update_rejects_constant_root": (
"""
Config :: struct { count usize }
Bad proc() type {
config Config :: { count = 1 }
config.count = 2
return [config.count]i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"assignment requires a mutable local binding",
),
"type_execution_index_update_rejects_readonly_array": (
"""
Bad proc() type {
counts [1]usize := [1]
counts[0] = 2
return [counts[0]]i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"indexed assignment requires a writable array element",
),
"type_execution_index_update_checks_bounds": (
"""
Bad proc() type {
counts [1]mut usize := [1]
counts[1] = 2
return [counts[0]]i16
}
main proc() Bad() { return [0] }
""", b"", b"index out of bounds",
),
"type_execution_index_update_checks_index_type": (
"""
Bad proc() type {
counts [1]mut usize := [1]
index u8 :: 0
counts[index] = 2
return [counts[0]]i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"array index must have type usize",
),
"type_execution_field_update_checks_exact_value_type": (
"""
Config :: struct { count usize }
Bad proc() type {
config Config := { count = 1 }
value u8 :: 2
config.count = value
return [config.count]i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"incompatible value type",
),
"type_execution_index_update_preserves_narrow_overflow": (
"""
Bad proc() type {
values [1]mut i8 := [127]
values[0] = values[0] + 1
return [usize(values[0])]i16
}
main proc() Bad() { return [0] }
""", b"", b"integer arithmetic overflow",
),
"type_execution_field_update_rejects_payload_capture_mutation": (
"""
Config :: struct { count usize }
Bad proc() type {
input ?Config :: { count = 1 }
if input |config| {
config.count = 2
return [config.count]i16
}
return i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"assignment requires a mutable local binding",
),
"type_execution_index_update_rejects_constant_array_root": (
"""
Bad proc() type {
counts [1]mut usize :: [1]
counts[0] = 2
return [counts[0]]i16
}
main proc() Bad() { return [0, 0] }
""", b"", b"indexed assignment requires a writable array element",
),
"type_execution_field_update_checks_member": (
"""
Config :: struct { count usize }
Bad proc() type {
config Config := { count = 1 }
config.missing = 2
return [config.count]i16
}
main proc() Bad() { return [0] }
""", b"", b"record has no such field",
),
"type_execution_optional_if_selects_storage_and_cache_identity": (
"""
Count :: alias ?usize
Storage proc(count Count) type {
if count |length| { return struct { values [length]i16 } }
else { return struct { value i16 = 2 } }
}
main proc() i16 {
value Storage(2) :: { values = [19, 21] }
same Storage(usize(2)) :: value
empty Storage(null) :: {}
return same.values[0] + same.values[1] + empty.value
}
""", b"42\n", None,
),
"type_execution_optional_payload_owned_aggregate_and_nested_capture": (
"""
Detail :: struct { values [2]i16, text string, count ?usize }
detail proc() ?Detail { return { values = [19, 21], text = "ok", count = 2 } }
Storage proc() type {
if detail() |payload| {
if payload.count |count| {
return struct {
values [count]i16
bias i16 = payload.values[0] + payload.values[1] + i16(payload.text.len)
}
}
}
return bool
}
main proc() i16 {
value Storage() :: { values = [0, 0] }
return value.bias
}
""", b"42\n", None,
),
"type_execution_optional_while_refreshes_capture_and_preserves_transfers": (
"""
next proc(count usize) ?usize {
if (count < 4) return count
return null
}
Storage proc() type {
count usize := 0
Result := i16
while next(count) |length| {
count = count + 1
if (length == 0) continue
if (length == 3) break
Result = [length]Result
}
pending ?usize := 2
while pending |length| {
pending = null
if (length != 2) return bool
count = count + length
}
return struct { values Result, bias i16 = i16(count) }
}
main proc() i16 {
value Storage() :: { values = [[17], [19]] }
return value.values[0][0] + value.values[1][0] + value.bias
}
""", b"42\n", None,
),
"type_execution_optional_absence_skips_invalid_bodies": (
"""
absent proc() ?i16 { return null }
null_pointer proc() ?@i16 { return null }
null_callback proc() ?@proc() i16 { return null }
Storage proc() type {
pointer ?@i16 :: null
while pointer |_| { return i8(128) }
if absent() |_| { return i8(128) }
else { return i16 }
}
main proc() i16 {
absent_pointer :: $(null_pointer())
absent_callback :: $(null_callback())
if absent_pointer |_| { return -1 }
if absent_callback |_| { return -2 }
value Storage() :: 42
return value
}
""", b"42\n", None,
),
"type_execution_optional_capture_retains_exact_payload_type": (
"""
narrow proc() ?i8 { return 127 }
Bad proc() type {
if narrow() |value| {
copy :: value
overflow :: copy + 1
return [usize(overflow)]i16
}
return i16
}
main proc() i16 { value Bad() :: 42
return value }
""", b"", b"integer arithmetic overflow",
),
"type_execution_optional_capture_is_immutable": (
"""
Bad proc(value ?usize) type {
if value |length| { length = 2 }
return i16
}
main proc() i16 { value Bad(1) :: 42
return value }
""", b"", b"assignment requires a mutable local binding",
),
"type_execution_optional_capture_requires_optional_guard": (
"""
Bad proc() type {
if true |_| { return i16 }
return bool
}
main proc() i16 { value Bad() :: 42
return value }
""", b"", b"condition must have type bool",
),
"type_execution_optional_capture_preserves_resolution_errors": (
"""
Bad proc(value ?usize) type {
if value |value| { return i16 }
return bool
}
main proc() i16 { value Bad(null) :: 42
return value }
""", b"", b"duplicate name",
),
"type_execution_optional_capture_loop_is_bounded": (
"""
Bad proc(value ?usize) type {
while value |_| {}
return i16
}
main proc() i16 { value Bad(1) :: 42
return value }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"generic_match_scalar_enum_and_range_selection": (
"""
Mode :: enum { pair, other }
answer proc($mode Mode, $count u8, value i16) i16 {
match true {
true: {
selected :: count
match selected {
0..2: return value.missing,
2..=3: {
return match mode {
.pair: value + 2,
.other: value.missing,
}
}
else: return false,
}
}
false: return value.missing,
}
}
main proc() i16 { return answer(.pair, 2, 40) }
""", b"42\n", None,
),
"generic_match_expression_selects_each_instance": (
"""
read proc($take bool, value i16) i16 {
return match take {
true: match take { true: value, false: value.missing },
false: value + 2,
}
}
main proc() i16 { return read(true, 20) + read(false, 20) }
""", b"42\n", None,
),
"generic_match_tagged_capture_exact_scalar_type": (
"""
Choice :: union(enum) { small i8, empty void }
exact proc(value i8) i16 { return i16(value) }
read proc($choice Choice, value i16) i16 {
return match choice {
.small |small|: exact(small) + value,
.empty: value.missing,
}
}
main proc() i16 { return read(.small{2}, 40) }
""", b"42\n", None,
),
"generic_match_tagged_capture_nested_owned_values": (
"""
Inner :: union(enum) { small i8, empty void }
Detail :: struct { inner Inner, values [2]i16, text string }
Choice :: union(enum) { detail Detail, unused void }
exact proc(value i8) i16 { return i16(value) }
read proc($choice Choice, value i16) i16 {
match choice {
.detail |detail|: {
copied Detail :: detail
if (copied.text.len != 5 or copied.text[0] != 111) return -1
return match detail.inner {
.small |small|: exact(small) + detail.values[0] + detail.values[1] + value,
.empty: value.missing,
}
}
.unused: return value.missing,
}
}
main proc() i16 {
return read(.detail{ inner = .small{2}, values = [19, 20], text = "owned" }, 1)
}
""", b"42\n", None,
),
"generic_match_selected_return_runs_cleanup": (
"""
read proc($take bool, total @mut i16, value i16) i16 {
defer total^ = total^ + 1
match take {
true: {
owned :: ["owned", "copy"]
defer total^ = total^ + i16(owned[1].len)
return value
}
false: return value.missing,
}
}
main proc() i16 {
total i16 := 0
value :: read(true, &total, 37)
return value + total
}
""", b"42\n", None,
),
"generic_match_selected_loop_transfers_run_cleanup": (
"""
read proc($take bool) i16 {
total i16 := 0
for (0..3) |index| {
match take {
true: {
owned :: ["owned", "copy"]
defer total = total + i16(owned[1].len)
if (index == 0) continue
break
}
false: return total.missing,
}
total = -100
}
return total + 34
}
main proc() i16 { return read(true) }
""", b"42\n", None,
),
"explicit_comptime_match_ordinary_call_without_templates": (
"""
selected proc() bool { return true }
main proc() i16 {
bias :: match $(selected()) { true: 2, false: false.missing }
match $(selected()) {
true: return 40 + bias,
false: return false,
}
}
""", b"42\n", None,
),
"generic_match_ordinary_call_still_checks_both_arms": (
"""
selected proc() bool { return true }
read proc($unused bool, value i16) i16 {
match selected() { true: return value, false: return false }
}
main proc() i16 { return read(true, 42) }
""", b"42\n", b"return does not match",
),
"ordinary_literal_match_still_checks_both_arms": (
"""
main proc() i16 {
match true { true: return 42, false: return false }
}
""", b"42\n", b"return does not match",
),
"generic_match_record_default_call_stays_runtime": (
"""
default_value proc() u8 { return 2 }
Choice :: struct { count u8, bias u8 = default_value() }
read proc($unused bool, value i16) i16 {
choice Choice :: { count = 2 }
match choice.bias { 2: return value, else: return false }
}
main proc() i16 { return read(true, 42) }
""", b"42\n", b"return does not match",
),
"generic_match_runtime_subject_still_checks_both_arms": (
"""
read proc($unused bool, take bool, value i16) i16 {
match take { true: return value, false: return false }
}
main proc() i16 { return read(true, true, 42) }
""", b"42\n", b"return does not match",
),
"generic_match_mutable_local_still_checks_both_arms": (
"""
read proc($take bool, value i16) i16 {
selected := take
match selected { true: return value, false: return false }
}
main proc() i16 { return read(true, 42) }
""", b"42\n", b"return does not match",
),
"generic_match_runtime_subject_runs_once": (
"""
selected proc(count @mut i16) bool {
count^ = count^ + 1
return true
}
read proc($unused bool, count @mut i16) i16 {
return match selected(count) { true: 41, false: 0 }
}
main proc() i16 {
count i16 := 0
value :: read(true, &count)
return value + count
}
""", b"42\n", None,
),
"generic_match_checks_untaken_overlap": (
"""
read proc($value u8) i16 {
return match value { 0: 42, 1..=3: 0, 3..5: 0, else: 0 }
}
main proc() i16 { return read(0) }
""", b"", b"duplicate or overlapping match pattern",
),
"generic_match_checks_exhaustiveness": (
"""
read proc($value bool) i16 { return match value { true: 42 } }
main proc() i16 { return read(true) }
""", b"", b"match is not exhaustive",
),
"generic_match_checks_untaken_capture_types": (
"""
Choice :: union(enum) { count usize, small i8, empty void }
read proc($choice Choice) i16 {
return match choice { .count, .small |value|: i16(value), .empty: 42 }
}
main proc() i16 { return read(.empty) }
""", b"", b"payload capture requires compatible nonvoid tagged union variants",
),
"generic_match_preserves_untaken_resolution_errors": (
"""
read proc($value bool) i16 {
return match value { true: 42, false: missing }
}
main proc() i16 { return read(true) }
""", b"42\n", b"unknown name",
),
"explicit_comptime_match_rejects_runtime_subject": (
"""
read proc(take bool) i16 {
return match $(take) { true: 42, false: 0 }
}
main proc() i16 { return read(true) }
""", b"", b"generic argument must be a compile-time value",
),
"type_match_tagged_capture_preserves_resolution_errors": (
"""
data proc() [2]i16 { return [40, 2] }
Choice :: union(enum) { payload struct { values [2]i16 }, empty void }
Storage proc(input Choice) type {
return match input {
.payload |data|: struct { bias i16 = data.values[1] },
.empty: bool,
}
}
main proc() Storage(.payload{ values = [40, 2] }) { return {} }
""", b"", b"duplicate name",
),
"type_match_tagged_capture_statements_and_cache_identity": (
"""
Tag :: enum(i16) { empty = -7, second = 3, count = 90 }
Choice :: union(Tag) { count usize, second usize, empty void }
choice proc() Choice { return .second{2} }
Storage proc(input Choice) type {
Result := i8
match input {
.count, .second |length|: {
Result = struct { values [length]i16 }
}
.empty: return struct { values [0]i16 },
}
return Result
}
main proc() i16 {
value Storage(choice()) :: { values = [40, 2] }
cached Storage(.second{2}) :: value
empty Storage(.empty) :: { values = [] }
return cached.values[0] + cached.values[1] + i16(empty.values.len)
}
""", b"42\n", None,
),
"type_match_tagged_capture_nested_expressions_and_storage": (
"""
Inner :: union(enum) { count usize, empty void }
Detail :: struct { inner Inner, wide bool, bias i16, text string }
Choice :: union(enum) { detail Detail, unused i8 }
Box proc(T type) type { return struct { value T } }
Storage proc(input Choice) type {
Element :: match input {
.detail |detail|: match detail.wide { true: i16, false: i8 },
.unused |small|: [small]bool,
}
return struct {
values [match input {
.detail |detail|: match detail.inner { .count |n|: n, .empty: usize(0) },
.unused |small|: usize(small),
}]Element
boxed Box(match input { .detail |detail|: Element, .unused: bool })
bias i16 = match input { .detail |detail|: detail.bias, .unused: i8(128) }
label string = match input { .detail |detail|: detail.text, .unused: "" }
}
}
main proc() i16 {
value Storage(.detail{ inner = .count{2}, wide = true, bias = 2, text = "owned" }) :: {
values = [19, 21], boxed = { value = 0 },
}
if (value.label.len != 5 or value.label[0] != 111) return -1
return value.values[0] + value.values[1] + value.boxed.value + value.bias
}
""", b"42\n", None,
),
"type_match_tagged_capture_loop_snapshots_and_transfers": (
"""
Choice :: union(enum) { count usize, empty void }
Nest proc() type {
Result := i16
current Choice := .count{0}
for (0..usize(4)) |index| {
current = .count{index}
match current {
.count |length|: {
if (length == 0) continue
if (length == 3) break
Result = [length]Result
}
.empty: return bool,
}
}
return Result
}
main proc() i16 {
value Nest() :: [[40], [2]]
return value[0][0] + value[1][0]
}
""", b"42\n", None,
),
"type_match_tagged_capture_checks_unselected_capture_types": (
"""
Choice :: union(enum) { count usize, small i8, empty void }
Bad proc(input Choice) type {
return match input { .count, .small |value|: [value]i16, .empty: bool }
}
main proc() Bad(.empty) { return true }
""", b"", b"payload capture requires compatible nonvoid tagged union variants",
),
"type_match_tagged_capture_preserves_exact_payload_type": (
"""
Choice :: union(enum) { small i8, empty void }
Bad proc(input Choice) type {
match input {
.small |value|: {
next :: value + 1
return [usize(next)]i16
}
.empty: return bool,
}
}
main proc() Bad(.small{127}) { return [] }
""", b"", b"integer arithmetic overflow",
),
"type_match_tagged_capture_is_immutable": (
"""
Choice :: union(enum) { count usize }
Bad proc(input Choice) type {
match input { .count |length|: {
length = 2
return [length]i16
} }
}
main proc() Bad(.count{1}) { return [0, 0] }
""", b"", b"mutable local binding",
),
"nested_type_match_failure_preserves_shared_return_types": (
"""
Original :: alias [2]i16
Broken proc() type {
Unused :: struct { value match true { true: i16 } }
return Original
}
main proc() i16 {
if (false) {
bad Broken() :: [0, 0]
return bad[0]
}
good Original :: [40, 2]
return good[0] + good[1]
}
""", b"42\n", b"match is not exhaustive",
),
"nested_type_matches_in_storage_calls_and_defaults": (
"""
Box proc(T type) type { return struct { value T } }
increment proc(value i16) i16 { return value + 2 }
Storage proc(wide bool) type {
return struct {
values [match wide { true: usize(2), false: usize(1) }]mut (match wide { true: i16, false: i8 })
boxed Box(match wide { true: i16, false: i8 })
callback @proc(value match wide { true: i16, false: i8 }) match wide { true: i16, false: i8 }
bias i16 = match (match wide { true: true, false: false }) { true: 0, false: i8(128) }
enabled bool = match wide { true: true, false: false }
label []u8 = match wide { true: "ok", false: "bad" }
fraction f64 = match wide { true: 0.5, false: 0.0 }
}
}
main proc() i16 {
value Storage(true) :: { values = [20, 20], boxed = { value = 0 }, callback = increment }
cached Storage(!false) :: value
if (!cached.enabled or cached.label[0] != 111 or cached.fraction != 0.5) return -1
return cached.callback(cached.values[0] + cached.values[1]) + cached.boxed.value + cached.bias
}
""", b"42\n", None,
),
"nested_type_matches_preserve_recursive_nominal_identity": (
"""
Node proc(wide bool) type {
return struct {
value match wide { true: i16, false: i8 }
next ?@match wide { true: Node(wide), false: bool } = match wide { true: null, false: null }
}
}
main proc() i16 {
leaf Node(true) :: { value = 40 }
head Node(!false) :: { value = 2, next = &leaf }
small Node(false) :: { value = 0 }
return head.value + head.next?.value + i16(small.value)
}
""", b"42\n", None,
),
"nested_type_matches_retain_loop_snapshots": (
"""
Nest proc(depth usize) type {
Result match true { true: type, false: i8 } := i16
count match true { true: usize, false: i8 } := depth
for (0..count) |index| {
Result = [match index { 0: usize(2), else: usize(1) }](match index {
0: Result,
else: match true { true: Result, false: i8(128) },
})
}
return Result
}
main proc() i16 {
values Nest(2) :: [[40, 2]]
return values[0][0] + values[0][1]
}
""", b"42\n", None,
),
"nested_type_matches_check_patterns_before_selecting": (
"""
Bad proc() type {
return struct { value [1](match true { true: i16 }) }
}
main proc() Bad() { return {} }
""", b"", b"match is not exhaustive",
),
"nested_type_matches_check_selected_defaults": (
"""
Bad proc() type {
return struct { value i8 = match true { true: 128, false: 0 } }
}
main proc() i16 {
value Bad() :: {}
return i16(value.value)
}
""", b"", b"numeric literal is outside",
),
"type_match_enum_storage_and_cache_identity": (
"""
Mode :: enum { tiny, pair, wide }
pair proc() Mode { return .pair }
Storage proc(mode Mode) type {
Result := i8
match mode {
.tiny: Result = i8,
.pair, .wide: {
Element :: i16
Result = [2]Element
}
}
return struct { values Result }
}
main proc() i16 {
value Storage(.pair) :: { values = [40, 2] }
cached Storage(pair()) :: value
tiny Storage(.tiny) :: { values = 1 }
return cached.values[0] + cached.values[1] + i16(tiny.values - 1)
}
""", b"42\n", None,
),
"type_match_ranges_transfers_and_mutable_subject": (
"""
Storage proc() type {
Result := i8
size usize := 0
for (0..usize(5)) |index| {
match index {
0: continue,
1..=2: {
Result = [1]Result
size = size + 1
}
else: break,
}
}
match size {
0..2: return bool,
else: return struct { values Result, bias i16 = i16(size) },
}
}
main proc() i16 {
value Storage() :: { values = [[40]] }
return i16(value.values[0][0]) + value.bias
}
""", b"42\n", None,
),
"type_match_type_expressions_and_untaken_bodies": (
"""
Select proc(wide bool) type {
Result := match wide {
true: match wide { true: i16, false: i8(128) },
false: i8,
}
Result = match wide { true: [2]Result, false: bool }
return match wide {
true: struct { values Result },
false: struct { value Result },
}
}
main proc() i16 {
wide Select(true) :: { values = [40, 2] }
narrow Select(false) :: { value = true }
if (narrow.value) return wide.values[0] + wide.values[1]
return 0
}
""", b"42\n", None,
),
"type_match_float_and_unsigned_boundaries": (
"""
Select proc() type {
Result := i8
match u64(18446744073709551615) {
0..18446744073709551615: Result = bool,
18446744073709551615: Result = i16,
else: Result = i8,
}
match -1.5 {
(-2.0)..(-1.0): return Result,
else: return bool,
}
}
main proc() Select() { return 42 }
""", b"42\n", None,
),
"type_match_checks_nonexhaustive_patterns": (
"""
Bad proc() type {
match true { true: return i16 }
return i8
}
main proc() Bad() { return 42 }
""", b"", b"match is not exhaustive",
),
"type_match_checks_overlapping_patterns": (
"""
Bad proc() type {
match u8(2) {
0..=2: return i16,
2..4: return i8,
else: return bool,
}
}
main proc() Bad() { return 42 }
""", b"", b"duplicate or overlapping match pattern",
),
"type_match_checks_unreachable_arms": (
"""
Bad proc() type {
return match true { else: i16, false: i8 }
}
main proc() Bad() { return 42 }
""", b"", b"match arm is unreachable",
),
"type_match_checks_pattern_types": (
"""
Bad proc() type {
match u8(2) { true: return i16, else: return i8 }
}
main proc() Bad() { return 42 }
""", b"", b"incompatible value type",
),
"type_match_checks_subject_types": (
"""
Bad proc() type {
return match "text" { else: i16 }
}
main proc() Bad() { return 42 }
""", b"", b"match subject",
),
"type_match_checks_selected_body": (
"""
Bad proc() type {
match false {
true: return i16,
false: {
count u8 := 255
count = count + 1
return [count]i16
}
}
}
main proc() Bad() { return 42 }
""", b"", b"integer arithmetic overflow",
),
"type_match_resolves_untaken_bodies": (
"""
Bad proc() type {
return struct { value match true { true: i16, false: missing } }
}
main proc() i16 {
value Bad() :: { value = 42 }
return value.value
}
""", b"42\n", b"unknown name",
),
"type_match_remains_bounded": (
"""
Bad proc() type {
while (true) {
match true { true: continue, false: return i16 }
}
}
main proc() Bad() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"type_execution_retains_existing_nominal_type_identity": (
"""
Original :: struct { value i16 }
Identity proc(T type) type {
Result := T
Same :: Result
return Same
}
Box proc(T type) type { return struct { value T } }
main proc() i16 {
first Original :: { value = 42 }
same Identity(Original) :: first
boxed Box(Identity(Original)) :: { value = same }
cached Box(Original) :: boxed
return cached.value.value
}
""", b"42\n", None,
),
"type_arrays_nested_copies_assignment_and_consumers": (
"""
Box proc(T type) type { return struct { value T } }
Selected proc() type {
explicit [2]mut [_]mut type := [[i8, bool], [u8, i16]]
inferred := [[i8, bool], [u8, i16]]
original :: explicit
copied [2]mut [_]mut type := explicit
(copied[0])[0] = bool
explicit[0] = [i16, u8]
inferred = [[i16, u8], [bool, i8]]
if (original[0][0] != i8 or copied[0][0] != bool) return bool
if (explicit[0][0] != i16 or inferred[1][0] != bool) return bool
return Box(explicit[0][0])
}
Storage proc() type {
types :: [Selected(), [2]i16]
return struct { item types[0], values types[1], bias i16 = 2 }
}
read proc(value Selected()) i16 { return value.value }
main proc() i16 {
value Storage() :: { item = { value = 19 }, values = [20, 1] }
return read(value.item) + value.values[0] + value.values[1] + value.bias
}
""", b"42\n", None,
),
"type_arrays_iteration_borrows_nested_places_and_copies_captures": (
"""
Selected proc() type {
types [2]mut type := [i8, bool]
Result := bool
for types |T, index| {
at usize :: index
if (at == 0) types[1] = i16
if (at == 1) Result = T
}
rows [2]mut [1]mut type := [[i8], [bool]]
for rows |row, index| {
copied := row
copied[0] = u8
if (row[0] == u8) return bool
if (index == 0) { (rows[1])[0] = Result }
if (index == 1 and row[0] != i16) return bool
}
empty [0]type :: []
for (empty) |_| return bool
if (empty.len != 0 or types.len != 2 or rows[0].len != 1) return bool
return rows[1][0]
}
main proc() i16 { value Selected() :: 42
return value
}
""", b"42\n", None,
),
"type_arrays_undefined_loop_initialization_generates_storage": (
"""
Storage proc() type {
types [2]mut type := undefined
if (types.len != 2) return bool
for (usize(0)..types.len) |index| { types[index] = i16 }
return struct { values [types.len]types[0], bias types[1] = 2 }
}
main proc() i16 {
value Storage() :: { values = [19, 21] }
same Storage() :: value
return same.values[0] + same.values[1] + same.bias
}
""", b"42\n", None,
),
"type_arrays_undefined_nested_updates_partial_copies_and_replacement": (
"""
Storage proc() type {
rows [2]mut [2]mut type := undefined
if (rows.len != 2 or rows[0].len != 2) return bool
(rows[0])[0] = i8
copied := rows
(rows[0])[1] = u8
rows[1] = [i8, bool]
(copied[0])[1] = i16
copied[1] = [bool, i16]
if (rows[0][0] != i8 or copied[0][0] != i8) return bool
if (rows[0][1] != u8 or rows[1][0] != i8 or rows[1][1] != bool) return bool
replacement [2]mut type := undefined
replacement = [i16, bool]
return struct { first copied[0][1], second copied[1][1], bias replacement[0] = 2 }
}
main proc() i16 {
value Storage() :: { first = 19, second = 21 }
return value.first + value.second + value.bias
}
""", b"42\n", None,
),
"type_arrays_undefined_empty_shapes_and_erased_generic_consumer": (
"""
empty_rows proc() [2]mut [0]mut type {
rows [2]mut [0]mut type := undefined
return rows
}
empty_outer proc() [0]mut [2]mut type {
rows [0]mut [2]mut type := undefined
return rows
}
row proc() [2]mut type {
types [2]mut type := undefined
rows :: empty_rows()
outer :: empty_outer()
if (rows.len != 2 or rows[0].len != 0 or rows[1].len != 0 or outer.len != 0) {
return [bool, bool]
}
for rows |empty| { for empty |_| { return [bool, bool] } }
types[0] = i16
types[1] = bool
return types
}
add proc($types [2]mut type, left types[0], right types[0]) types[0] {
enabled types[1] :: true
if (enabled) return left + right
return 0
}
forward proc(value i16) i16 { return add(row(), value, 2) }
main proc() i16 { return forward(40) }
""", b"42\n", None,
),
"type_arrays_undefined_reject_premature_leaf_read": (
"""
Bad proc() type {
types [2]mut type := undefined
types[0] = i16
return types[1]
}
main proc() Bad() { return 42 }
""", b"", b"local value was read before initialization",
),
"type_arrays_undefined_reject_partial_return": (
"""
rows proc() [2]mut [1]mut type {
types [2]mut [1]mut type := undefined
(types[0])[0] = i16
return types
}
main proc() rows()[0][0] { return 42 }
""", b"", b"local value was read before initialization",
),
"type_arrays_undefined_reject_partial_argument": (
"""
Selected proc(types [2]mut [1]mut type) type { return i16 }
Bad proc() type {
types [2]mut [1]mut type := undefined
(types[0])[0] = i16
return Selected(types)
}
main proc() Bad() { return 42 }
""", b"", b"local value was read before initialization",
),
"type_arrays_undefined_reject_partial_erased_argument": (
"""
Selected proc($types [2]mut type) type { return i16 }
Bad proc() type {
types [2]mut type := undefined
types[0] = i16
return Selected(types)
}
main proc() Bad() { return 42 }
""", b"", b"local value was read before initialization",
),
"type_arrays_undefined_copy_does_not_observe_later_initialization": (
"""
Bad proc() type {
types [2]mut type := undefined
types[0] = i16
copied :: types
types[1] = bool
return copied[1]
}
main proc() Bad() { return 42 }
""", b"", b"local value was read before initialization",
),
"type_arrays_undefined_reject_readonly_element_write": (
"""
Bad proc() type {
types [1]type := undefined
types[0] = i16
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"indexed assignment requires a writable array element",
),
"type_arrays_undefined_reject_inferred_length": (
"""
Bad proc() type {
types [_]mut type := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"array length must be a nonnegative supported compile-time integer",
),
"type_arrays_undefined_empty_outer_rejects_inferred_child_length": (
"""
Bad proc() type {
types [0]mut [_]mut type := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"array length must be a nonnegative supported compile-time integer",
),
"type_arrays_undefined_construction_is_bounded": (
"""
Bad proc() type {
types [1000000000]mut type := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"type_arrays_undefined_nested_empty_construction_is_bounded": (
"""
Bad proc() type {
types [100]mut [100]mut [0]mut type := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"value_arrays_undefined_loop_initialization_generates_storage": (
"""
Storage proc() type {
rows [2]mut [2]mut usize := undefined
for (usize(0)..rows.len) |row| {
for (usize(0)..rows[row].len) |column| { (rows[row])[column] = row + column + 1 }
}
return struct { values [rows[0][1]]i16, bias i16 = i16(rows[1][0]) }
}
main proc() i16 {
value Storage() :: { values = [19, 21] }
same Storage() :: value
return same.values[0] + same.values[1] + same.bias
}
""", b"42\n", None,
),
"value_arrays_undefined_partial_copies_and_whole_replacement": (
"""
Storage proc() type {
rows [2]mut [2]mut i16 := undefined
(rows[0])[0] = 19
copied := rows
(rows[0])[1] = 1
rows[1] = [2, 3]
(copied[0])[1] = 21
copied[1] = [1, 1]
replacement [2]mut i16 := undefined
replacement = copied[1]
if (rows[0][1] != 1 or rows[1][0] != 2) return bool
return struct { value i16 = copied[0][0] + copied[0][1] + replacement[0] + replacement[1] }
}
main proc() i16 { value Storage() :: {}
return value.value
}
""", b"42\n", None,
),
"value_arrays_undefined_strings_optionals_records_and_unions": (
"""
Item :: struct { text string, amount ?i16, values [1]mut i16 }
Choice :: union(enum) { value i16, empty void }
Storage proc() type {
words [2]mut string := undefined
words[0] = "ok"
words[1] = "yes"
options [2]mut ?i16 := undefined
options[0] = null
options[1] = 37
items [1]mut Item := undefined
items[0] = { text = words[0], amount = options[0], values = [0] }
items[0].amount = options[1]
items[0].values[0] = 37
choices [1]mut Choice := undefined
choices[0] = .empty
choices[0] = .value{items[0].values[0]}
amount :: match choices[0] { .value |value|: value, .empty: i16(0) }
return struct { value i16 = amount + items[0].amount? - 37 + i16(items[0].text.len + words[1].len) }
}
main proc() i16 { value Storage() :: {}
return value.value
}
""", b"42\n", None,
),
"value_arrays_undefined_empty_shapes_and_type_array_producer": (
"""
Rows proc() [1]mut type {
rows [2]mut [0]mut i16 := undefined
outer [0]mut [2]mut usize := undefined
copied :: rows
if (copied.len != 2 or copied[0].len != 0 or outer.len != 0) return [bool]
for rows |row| { for row |_| { return [bool] } }
counts [1]mut usize := undefined
counts[0] = rows.len
return [struct { values [counts[0]]i16, bias i16 = 2 }]
}
main proc() i16 {
value Rows()[0] :: { values = [19, 21] }
return value.values[0] + value.values[1] + value.bias
}
""", b"42\n", None,
),
"value_arrays_undefined_reject_premature_leaf_read": (
"""
Bad proc() type {
values [2]mut usize := undefined
values[0] = 2
return [values[1]]i16
}
main proc() Bad() { return [] }
""", b"", b"local value was read before initialization",
),
"value_arrays_undefined_reject_partial_argument": (
"""
Selected proc(values [2]mut usize) type { return [values[0]]i16 }
Bad proc() type {
values [2]mut usize := undefined
values[0] = 2
return Selected(values)
}
main proc() Bad() { return [19, 23] }
""", b"", b"local value was read before initialization",
),
"value_arrays_undefined_copy_does_not_observe_later_initialization": (
"""
Bad proc() type {
values [2]mut usize := undefined
values[0] = 2
copied :: values
values[1] = 1
return [copied[1]]i16
}
main proc() Bad() { return [] }
""", b"", b"local value was read before initialization",
),
"value_arrays_undefined_reject_readonly_binding": (
"""
Bad proc() type {
values [1]mut usize :: undefined
values = [2]
return i16
}
main proc() Bad() { return 42 }
""", b"", b"assignment requires a mutable local binding",
),
"value_arrays_undefined_reject_readonly_elements": (
"""
Bad proc() type {
values [1]usize := undefined
values[0] = 2
return i16
}
main proc() Bad() { return 42 }
""", b"", b"indexed assignment requires a writable array element",
),
"value_arrays_undefined_reject_wrong_leaf_type": (
"""
Bad proc() type {
values [1]mut usize := undefined
wrong u8 :: 2
values[0] = wrong
return i16
}
main proc() Bad() { return 42 }
""", b"", b"",
),
"value_arrays_undefined_reject_wrong_index_type": (
"""
Bad proc() type {
values [1]mut usize := undefined
index u8 :: 0
values[index] = 2
return i16
}
main proc() Bad() { return 42 }
""", b"", b"array index must have type usize",
),
"value_arrays_undefined_reject_out_of_bounds_write": (
"""
Bad proc() type {
values [1]mut usize := undefined
values[1] = 2
return i16
}
main proc() Bad() { return 42 }
""", b"", b"index out of bounds",
),
"value_arrays_undefined_preserve_narrow_overflow": (
"""
Bad proc() type {
values [1]mut i8 := undefined
values[0] = 127
values[0] = values[0] + 1
return i16
}
main proc() Bad() { return 42 }
""", b"", b"integer arithmetic overflow",
),
"value_arrays_undefined_construction_is_bounded": (
"""
Bad proc() type {
values [1000000000]mut usize := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"value_arrays_undefined_nested_empty_construction_is_bounded": (
"""
Bad proc() type {
values [100]mut [100]mut [0]mut usize := undefined
return i16
}
main proc() Bad() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"value_arrays_undefined_reject_invalid_empty_element_annotation": (
"""
Storage proc() type {
values [0]mut void := undefined
return i16
}
main proc() Storage() { return 42 }
""", b"42\n", b"array element annotations",
),
"type_arrays_only_execute_selected_bodies": (
"""
Selected proc(ok bool) type {
types :: [i16]
if (ok) return types[0]
return types[1]
}
main proc() i16 { value Selected(true) :: 42
return value
}
""", b"42\n", None,
),
"type_arrays_selected_invalid_body": (
"""
Selected proc(ok bool) type {
types :: [i16]
if (ok) return types[0]
return types[1]
}
main proc() Selected(false) { return 42 }
""", b"", b"index out of bounds",
),
"type_arrays_read_requires_usize_index": (
"""
Bad proc() type {
types :: [i16]
index u8 :: 0
return types[index]
}
main proc() Bad() { return 42 }
""", b"", b"array index must have type usize",
),
"type_arrays_write_checks_bounds": (
"""
Bad proc() type {
types [1]mut type := [i16]
types[1] = bool
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"index out of bounds",
),
"type_arrays_write_requires_usize_index": (
"""
Bad proc() type {
types [1]mut type := [i16]
index u8 :: 0
types[index] = bool
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"array index must have type usize",
),
"type_arrays_write_requires_mutable_elements": (
"""
Bad proc() type {
types [1]type := [i16]
types[0] = bool
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"indexed assignment requires a writable array element",
),
"type_arrays_nested_write_requires_mutable_inner_elements": (
"""
Bad proc() type {
types [1]mut [1]type := [[i16]]
(types[0])[0] = bool
return types[0][0]
}
main proc() Bad() { return 42 }
""", b"", b"indexed assignment requires a writable array element",
),
"type_arrays_whole_assignment_requires_mutable_binding": (
"""
Bad proc() type {
types :: [i16]
types = [bool]
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"assignment requires a mutable local binding",
),
"type_arrays_whole_assignment_checks_shape": (
"""
Bad proc() type {
types := [[i16]]
types = [[i16, bool]]
return types[0][0]
}
main proc() Bad() { return 42 }
""", b"", b"array literal length does not match its type",
),
"type_arrays_indexed_assignment_checks_shape": (
"""
Bad proc() type {
types [1]mut [1]mut type := [[i16]]
types[0] = [i16, bool]
return types[0][0]
}
main proc() Bad() { return 42 }
""", b"", b"array literal length does not match its type",
),
"type_arrays_indexed_assignment_checks_value": (
"""
Bad proc() type {
types [1]mut type := [i16]
types[0] = 42
return types[0]
}
main proc() Bad() { return 42 }
""", b"", b"incompatible value type",
),
"type_arrays_inferred_nested_counts_reject_ragged_initialization": (
"""
Bad proc() type {
types [2]mut [_]mut type := [[i8], [i16, bool]]
return types[1][0]
}
main proc() Bad() { return 42 }
""", b"", b"array literal length does not match its type",
),
"type_arrays_preserve_anonymous_nominal_identity_across_reads_and_copies": (
"""
Selected proc() type {
types :: [struct { value i16 }, struct { value i16 }]
copied :: types
if (types[0] != copied[0] or types[0] == types[1]) return bool
return struct { first types[0], second copied[0] }
}
main proc() i16 {
value Selected() :: { first = { value = 19 }, second = { value = 23 } }
copied := value.first
copied = value.second
return value.first.value + copied.value
}
""", b"42\n", None,
),
"type_arrays_empty_shapes_validate_child_lengths": (
"""
Bad proc() type {
types [0][-1]type :: []
return i16
}
main proc() Bad() { return 42 }
""", b"", b"array length must be a nonnegative supported compile-time integer",
),
"type_array_procedure_nested_results_in_signatures_storage_and_defaults": (
"""
Row :: alias [2]type
row proc(wide bool) Row {
if (wide) return [i16, [2]i16]
return [i8, [2]i8]
}
rows proc() [2]Row { return [row(true), row(false)] }
Storage :: struct { values rows()[0][1], bias rows()[0][0] = 2 }
read proc(value rows()[0][0]) rows()[0][0] { return value }
main proc() i16 {
value Storage :: { values = [19, 21] }
small rows()[1][1] :: [0, 0]
return read(value.values[0]) + value.values[1] + value.bias + i16(small[0])
}
""", b"42\n", None,
),
"type_array_procedure_dependent_lengths_and_ordinary_array_inputs": (
"""
identity proc($N usize, types [N]type) [N]type { return types }
row proc() [2]type { return identity(2, identity(1 + 1, [i16, bool])) }
Box proc($N usize, types [N]type) type {
return struct { value types[0], enabled types[1] = true }
}
main proc() i16 {
value Box(2, row()) :: { value = 42 }
same Box(1 + 1, [i16, bool]) :: value
if (same.enabled) return same.value
return 0
}
""", b"42\n", None,
),
"type_array_procedure_erased_runtime_generic_parameters": (
"""
row proc() [2]type { return [i16, bool] }
add proc($types [2]type, left types[0], right types[0]) types[0] {
enabled types[1] :: true
if (enabled) return left + right
return 0
}
forward proc(value i16) i16 { return add(row(), value, 2) }
main proc() i16 { return forward(40) }
""", b"42\n", None,
),
"type_array_procedure_inputs_results_and_cache_are_by_value": (
"""
change proc(types [1]mut [2]mut type) [1]mut [2]mut type {
copied := types
(copied[0])[0] = bool
return copied
}
seed proc() [1]mut [2]mut type { return [[i16, i8]] }
Selected proc() type {
original [1]mut [2]mut type := $(seed())
changed := change(original)
(changed[0])[1] = u8
cached := change(seed())
fresh := seed()
if (original[0][0] != i16 or fresh[0][0] != i16) return bool
if (cached[0][0] != bool or cached[0][1] != i8) return bool
if (changed[0][1] != u8) return bool
return original[0][0]
}
main proc() Selected() { return 42 }
""", b"42\n", None,
),
"type_array_procedure_cache_canonical_leaves_and_nominal_identity": (
"""
Original :: struct { value i16 }
Same :: alias Original
leaf proc() type { return Original }
identity proc(types [2]type) [2]type { return types }
Box proc(types [2]type) type { return struct { first types[0], second types[1] } }
Selected proc() type {
leaves :: identity([struct { value i16 }, struct { value i16 }])
copied :: identity(leaves)
if (leaves[0] == leaves[1] or leaves[0] != copied[0]) return bool
if (Box([leaves[0], leaves[0]]) == Box([leaves[1], leaves[1]])) return bool
return Box([copied[0], leaves[0]])
}
main proc() i16 {
canonical Box(identity([Same, leaf()])) :: {
first = { value = 19 }, second = { value = 21 },
}
cached Box([Original, Original]) :: canonical
nominal Selected() :: { first = { value = 1 }, second = { value = 1 } }
copy := nominal.first
copy = nominal.second
return cached.first.value + cached.second.value + nominal.first.value + copy.value
}
""", b"42\n", None,
),
"type_array_procedure_empty_nested_shapes": (
"""
empty proc() [0]type { return [] }
rows proc(types [0]type) [2][0]type { return [types, empty()] }
outer proc() [0][2]type { return [] }
Selected proc(types [2][0]type, absent [0][2]type) type {
if (types.len != 2 or types[0].len != 0 or absent.len != 0) return bool
for types |row| { for row |_| { return bool } }
return i16
}
main proc() Selected(rows(empty()), outer()) { return 42 }
""", b"42\n", None,
),
"type_array_procedure_rejects_input_shape": (
"""
first proc(types [2]type) type { return types[0] }
main proc() first([i16]) { return 42 }
""", b"", b"array literal length does not match its type",
),
"type_array_procedure_rejects_input_leaf": (
"""
first proc(types [1]type) type { return types[0] }
main proc() first([42]) { return 42 }
""", b"", b"incompatible value type",
),
"type_array_procedure_rejects_parameter_mutability_mismatch": (
"""
row proc() [1]mut type { return [i16] }
first proc(types [1]type) type { return types[0] }
main proc() first(row()) { return 42 }
""", b"", b"incompatible value type",
),
"type_array_procedure_rejects_result_shape": (
"""
bad proc() [1][2]type { return [[i16]] }
main proc() bad()[0][0] { return 42 }
""", b"", b"array literal length does not match its type",
),
"type_array_procedure_rejects_result_leaf": (
"""
bad proc() [1]type { return [42] }
main proc() bad()[0] { return 42 }
""", b"", b"incompatible value type",
),
"type_array_procedure_result_index_checks_bounds": (
"""
row proc() [1]type { return [i16] }
main proc() row()[1] { return 42 }
""", b"", b"index out of bounds",
),
"type_array_procedure_result_index_requires_usize": (
"""
row proc() [1]type { return [i16] }
main proc() row()[u8(0)] { return 42 }
""", b"", b"array index must have type usize",
),
"type_array_procedure_rejects_runtime_dependency": (
"""
row proc(wide bool) [1]type {
if (wide) return [i16]
return [i8]
}
read proc(wide bool) i16 {
value row(wide)[0] :: 42
return i16(value)
}
main proc() i16 { return read(true) }
""", b"", b"generic argument must be a compile-time value",
),
"type_array_procedure_requires_all_ordinary_arguments": (
"""
row proc(ignored usize) [1]type { return [i16] }
main proc() row()[0] { return 42 }
""", b"", b"argument count does not match",
),
"type_array_procedure_nested_execution_shares_step_limit": (
"""
row proc(count usize) [1]type {
for (0..count) |_| { }
return [i16]
}
Selected proc() type {
for (0..usize(100)) |index| { types :: row(index + 100) }
return i16
}
main proc() Selected() { return 42 }
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"type_execution_mutable_types_and_nested_producers": (
"""
Nest proc(T type, depth usize) type {
Result type := T
count usize := 0
while (count < depth) {
Result = [2]Result
count = count + 1
}
return Result
}
Box proc(T type) type { return struct { value T } }
main proc() i16 {
value Box(Nest(i16, 2)) :: { value = [[20, 20], [1, 1]] }
same Box(Nest(i16, 1 + 1)) :: value
return same.value[0][0] + same.value[0][1] + same.value[1][0] + same.value[1][1]
}
""", b"42\n", None,
),
"type_execution_range_captures_scope_and_transfers": (
"""
Storage proc() type {
Result := i8
size usize := 0
for (0..usize(5)) |index| {
if (index == 0) continue
if (index == 3) break
next :: [index]Result
Result = next
size = size + 1
}
while (size < 3) {
size = size + 1
if (size == 3) continue
Result = bool
}
return struct { values Result, bias i16 = i16(size) }
}
main proc() i16 {
value Storage() :: { values = [[19], [20]] }
return i16(value.values[0][0]) + i16(value.values[1][0]) + value.bias
}
""", b"42\n", None,
),
"type_execution_early_return_and_recursive_calls": (
"""
Nest proc(T type, depth usize) type {
if (depth == 0) return T
return [2]Nest(T, depth - 1)
}
Select proc(wide bool) type {
Result := i8
if (wide) {
Result = Nest(i16, 1)
return Result
} else { Result = [2]Result }
return Result
}
main proc() i16 {
wide Select(true) :: [40, 2]
narrow Select(false) :: [1, 1]
return wide[0] + wide[1] + i16(narrow[0] - narrow[1])
}
""", b"42\n", None,
),
"type_execution_inclusive_narrow_range_does_not_overflow": (
"""
Storage proc() type {
count usize := 0
for (u8(254)..=u8(255)) |_| count = count + 1
for (i8(2)..i8(-2)) |_| count = 99
return [count]i16
}
main proc() i16 {
values Storage() :: [40, 2]
return values[0] + values[1]
}
""", b"42\n", None,
),
"type_execution_rejects_constant_assignment": (
"""
Bad proc() type {
T :: i16
T = bool
return T
}
main proc() i16 {
value Bad() :: 42
return value
}
""", b"", b"assignment requires a mutable local binding",
),
"type_execution_rejects_value_in_type_local": (
"""
Bad proc() type {
T := i16
T = 42
return T
}
main proc() i16 {
value Bad() :: 42
return value
}
""", b"", b"incompatible value type",
),
"type_execution_preserves_scalar_type_and_overflow": (
"""
Bad proc() type {
count u8 := 255
count = count + 1
return [count]i16
}
main proc() i16 {
value Bad() :: 42
return value
}
""", b"", b"integer arithmetic overflow",
),
"type_execution_checks_guard_operands": (
"""
Bad proc() type {
T := i16
while (false and 1) T = bool
return T
}
main proc() i16 {
value Bad() :: 42
return value
}
""", b"", b"operator requires compatible operand types",
),
"type_execution_is_bounded": (
"""
Bad proc() type {
counter usize := 0
while (counter >= 0) counter = counter + 1
return i16
}
main proc() i16 {
value Bad() :: 42
return value
}
""", b"", b"compile-time execution exceeds its recursion or step limit",
),
"type_producer_ordinary_inputs_generate_storage_and_cache_identity": (
"""
Fixed proc(T type, count usize) type { return struct { values [count]T } }
main proc() i16 {
value Fixed(i16, 2) :: { values = [40, 2] }
same Fixed(i16, 1 + 1) :: value
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"type_producer_mixes_explicit_and_ordinary_constant_inputs": (
"""
Fixed proc($T type, count usize) type { return [count]T }
Choose proc(wide bool) type {
if (wide) return Fixed(i16, 2)
return Fixed(i8, 2)
}
main proc() i16 {
wide Choose(true) :: [40, 2]
narrow Choose(false) :: [1, 1]
return wide[0] + wide[1] + i16(narrow[0] - narrow[1])
}
""", b"42\n", None,
),
"type_producer_computed_ordinary_inputs_reuse_typed_execution": (
"""
count proc(seed usize) usize {
result := seed
while (result < 2) result = result + 1
return result
}
Fixed proc(size usize) type { return struct { values [size]i16 } }
main proc() i16 {
first Fixed(count(0)) :: { values = [40, 2] }
same Fixed(2) :: first
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"type_producer_ordinary_inputs_preserve_nominal_separation": (
"""
Tag proc(value usize) type { return struct { value i16 } }
main proc() bool { return $(Tag(1) != Tag(2)) }
""", b"true\n", None,
),
"type_producer_dependent_contextual_ordinary_input": (
"""
Fixed proc($T type, $N usize, data [N]T) type {
return struct { values [N]T = data }
}
main proc() i16 {
value Fixed(i16, 2, [40, 2]) :: {}
same Fixed(i16, 2, [20 + 20, 2]) :: value
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"type_producer_rejects_runtime_dependency": (
"""
Fixed proc(size usize) type { return [size]i16 }
read proc(size usize) i16 {
data Fixed(size) :: [40, 2]
return data[0] + data[1]
}
main proc() i16 { return read(2) }
""", b"", b"generic argument must be a compile-time value",
),
"type_producer_checks_unused_ordinary_input_range": (
"""
Tag proc(ignored u8) type { return struct { value i16 } }
main proc() i16 {
value Tag(256) :: { value = 42 }
return value.value
}
""", b"", b"numeric literal is outside",
),
"type_producer_checks_erased_ordinary_input_exact_type": (
"""
Tag proc(ignored i16) type { return struct { value i16 } }
main proc() i16 {
wrong u16 :: 1
first Tag(1) :: { value = 42 }
same Tag(wrong) :: first
return same.value
}
""", b"42\n", b"incompatible value type",
),
"type_producer_requires_all_ordinary_inputs": (
"""
Tag proc(ignored i16) type { return struct { value i16 } }
main proc() i16 {
value Tag() :: { value = 42 }
return value.value
}
""", b"", b"argument count does not match",
),
"type_producer_ordinary_input_trap_keeps_original_diagnostic": (
"""
count proc() usize {
high usize :: 18446744073709551615
return high + 1
}
Fixed proc(size usize) type { return [size]i16 }
main proc() i16 {
value Fixed(count()) :: [40, 2]
return value[0] + value[1]
}
""", b"", b"integer arithmetic overflow",
),
"comptime_composed_type_identity_is_order_independent_and_cached": (
"""
Left :: enum { left }
Right :: enum { right }
Box proc($T type) type { return struct { value T } }
identical proc($A, $B type) bool { return A == B }
main proc() bool {
first Box(Left | Right) :: { value = .left }
same Box(Right | Left | Left) :: first
return (
identical(Left | Right, Right | Left | Left)
and identical(Left, Left | Left) and same.value == .left
)
}
""", b"true\n", None,
),
"comptime_callback_branch_uses_optional_function_identity": (
"""
Callback :: alias @proc(value i16) i16
increment proc(value i16) i16 { return value + 1 }
apply proc($callback ?Callback, value i16) i16 {
if $(callback == null) { return value }
else { return callback?(value) }
}
main proc() i16 { return apply(null, 40) + apply(increment, 1) }
""", b"42\n", None,
),
"comptime_computed_callbacks_preserve_optional_presence_and_calls": (
"""
Callback :: alias @proc(value i16) i16
increment proc(value i16) i16 { return value + 1 }
decrement proc(value i16) i16 { return value - 1 }
choose proc(up bool) Callback {
callback Callback := decrement
if (up) callback = increment
return callback
}
maybe proc(present bool) ?Callback {
if (present) return choose(true)
return null
}
nested proc(present bool) ??Callback {
if (present) return some!(maybe(true))
return some!(null)
}
main proc() [6]i16 {
up :: $(choose(true))
down :: $(choose(false))
optional :: $(maybe(true))
absent :: $(maybe(false))
outer :: $(nested(false))
inner :: $(nested(true))
return [up(41), down(43), (optional?)(41), ((inner?)?)(41),
(if (absent == null) i16(42) else i16(0)),
(if (outer != null and outer? == null) i16(42) else i16(0))]
}
""", b"[42, 42, 42, 42, 42, 42]\n", None,
),
"comptime_callback_aggregates_cache_source_identity_and_generate_defaults": (
"""
Callback :: alias @proc(value i16) i16
increment proc(value i16) i16 { return value + 1 }
decrement proc(value i16) i16 { return value - 1 }
Callbacks :: struct { items [2]Callback, optional ?Callback }
Choice :: union(enum) { callback Callback, empty void }
Failure :: union(enum) { callback Callback }
make proc(reverse bool) Callbacks {
if (reverse) return { items = [decrement, increment], optional = null }
return { items = [increment, decrement], optional = increment }
}
choice proc() Choice { return .callback{increment} }
result proc(fail bool) Callback ! Failure {
if (fail) return .callback{decrement}
return increment
}
Box proc($callbacks Callbacks) type {
return struct { callbacks Callbacks = callbacks }
}
main proc() [6]i16 {
first Box(make(false)) :: {}
same Box(Callbacks { items = [increment, decrement], optional = increment }) :: first
other Box(make(true)) :: {}
selected :: $(choice())
success :: $(result(false)) catch increment
failure :: $(result(true)) catch |err| err.callback
return [same.callbacks.items[0](41), same.callbacks.optional?(41),
other.callbacks.items[0](43), selected.callback(41),
success(41), failure(43)]
}
""", b"[42, 42, 42, 42, 42, 42]\n", None,
),
"comptime_computed_callback_signatures_remain_checked": (
"""
Callback :: alias @proc(value i16) i16
wrong proc(value u8) u8 { return value }
choose proc() Callback { return wrong }
main proc() i16 { return $(choose())(42) }
""", b"", b"return does not match the function result type",
),
"comptime_computed_callback_traps_keep_declaration_provenance": (
"""
Callback :: alias @proc(value i8) i8
increment proc(value i8) i8 { return value + 1 }
choose proc() Callback { return increment }
main proc() i8 { return $(choose())(127) }
""", b"", b":2:38: runtime trap: integer arithmetic overflow",
),
"comptime_branch_rejects_runtime_guard_dependencies": (
"""
answer proc(take bool) i16 {
if $(take) { return 42 } else { return 0 }
}
main proc() i16 { return answer(true) }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_branch_checks_short_circuited_guard_operands": (
"""
main proc() i16 {
if $(true or 1) { return 42 } else { return 0 }
}
""", b"", b"operator requires compatible operand types",
),
"specialized_type_branches_check_only_selected_storage": (
"""
count proc($T type, value T) i16 {
if (T == i16) return value else return value.count
}
Box :: struct { count i16 }
main proc() i16 { return count(i16, 40) + count(Box, Box { count = 2 }) }
""", b"42\n", None,
),
"explicit_comptime_branch_without_templates": (
"""
enabled proc() bool { return true }
main proc() i16 {
if $(enabled()) { return 42 } else { return false }
}
""", b"42\n", None,
),
"specialized_branches_skip_recursive_instantiation_and_traps": (
"""
answer proc($stop bool) i16 {
if (stop) return 42 else return answer(false)
}
main proc() i16 {
if $(false) { return $(i8(128)) }
return answer(true)
}
""", b"42\n", None,
),
"specialized_branches_preserve_runtime_conditions": (
"""
answer proc($T type, value T, take bool) i16 {
if (T != i16) return value.count
if (take) return value else return 2
}
main proc() i16 { return answer(i16, 40, true) + answer(i16, 99, false) }
""", b"42\n", None,
),
"specialized_branch_keeps_scope_and_cleanup": (
"""
change proc($take bool, value @mut i16) void {
if (take) {
defer value^ = value^ + 2
value^ = 40
}
else value^ = 0
}
main proc() i16 {
value i16 := 0
change(true, &value)
return value
}
""", b"42\n", None,
),
"comptime_type_equality_preserves_aliases_and_nominal_identity": (
"""
First :: struct { value i16 }
Second :: struct { value i16 }
Same :: alias First
identical proc($A, $B type) bool { return A == B }
main proc() bool {
return (
identical(First, Same) and !identical(First, Second)
and $(@mut i16 == @mut i16) and $(@mut i16 != @i16)
and $([2]i16 == [1 + 1]i16) and $([2]i16 != [2]u16)
)
}
""", b"true\n", None,
),
"specialized_branch_retains_guard_type_errors": (
"""
answer proc($take bool) i16 {
if (take or 1) return 42 else return false
}
main proc() i16 { return answer(true) }
""", b"", b"operator requires compatible operand types",
),
"specialized_branch_retains_selected_body_errors": (
"""
answer proc($T type, value T) i16 {
if (T == i16) return value.missing
return 42
}
main proc() i16 { return answer(i16, 0) }
""", b"", b"field selection requires a record or tuple",
),
"ordinary_constant_branch_still_checks_both_arms": (
"""
main proc() i16 {
if (true) return 42 else return false
}
""", b"42\n", b"return does not match",
),
"specialized_branch_runtime_call_remains_reachable": (
"""
fail proc(value i8) bool { return value + 1 == 0 }
answer proc($T type) i16 {
if (fail(127)) return 0
return 42
}
main proc() i16 { return answer(i16) }
""", b"", b"integer arithmetic overflow",
),
"comptime_contextual_aggregate_arguments_keep_dependent_types": (
"""
sum proc(items [2]i16) i16 { return items[0] + items[1] }
answer proc($T type, $N usize, $items [N]T) T { return items[0] + items[1] }
main proc() i16 { return answer(i16, 2, [20, 20]) + $(sum([1, 1])) }
""", b"42\n", None,
),
"comptime_zero_cell_aggregates_keep_logical_lengths": (
"""
Empty :: struct {}
Storage :: struct { items [3]Empty, empty [0]i16 }
make proc() Storage { return Storage { items = [{}, {}, {}], empty = [] } }
main proc() usize {
value :: $(make())
return value.items.len + value.empty.len
}
""", b"3\n", None,
),
"explicit_comptime_float_arithmetic_keeps_ieee_equality": (
"""
main proc() bool { return $(1.5 + 2.5) == 4.0 and $(-0.0 == 0.0) and $(4 / 2) == 2.0 }
""", b"true\n", None,
),
"comptime_aggregate_specialization_uses_normalized_values": (
"""
Config :: struct { count usize, bias i16 = 2 }
config proc() Config {
result Config := { count = 0 }
while (result.count < 2) result.count = result.count + 1
return result
}
Fixed proc($settings Config) type {
return struct { values [settings.count]i16 }
}
main proc() i16 {
first Fixed(config()) :: { values = [40, 2] }
same Fixed({ bias = 2, count = 2 }) :: first
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"comptime_array_arguments_and_explicit_copy_isolation": (
"""
values proc() [2]mut i16 {
result [2]mut i16 := [0, 2]
for (0..usize(2)) |index| result[index] = result[index] + 20
return result
}
sum proc($items [2]mut i16) i16 { return items[0] + items[1] }
main proc() i16 {
first := $(values())
copy := first
first[0] = 99
return sum(values()) + copy[0] - 20
}
""", b"42\n", None,
),
"explicit_comptime_without_templates_preserves_nested_values": (
r"""
Kind :: enum { ready, empty }
Inner :: struct { text string, count ?i16 }
Packet :: struct { rows [2]mut Inner, kind Kind, weight f64 }
make proc() Packet {
result Packet := {
rows = [{ text = "a\"\\\x00é", count = 20 }, { text = "ok", count = null }],
kind = .ready, weight = 2.5,
}
result.rows[0].count = 40
return result
}
main proc() i16 {
packet := $(make())
copy :: packet
packet.rows[0].text = "changed"
if (copy.kind != .ready or copy.weight != 2.5 or copy.rows[1].count != null) return 0
return copy.rows[0].count? + i16(copy.rows[1].text.len)
}
""", b"42\n", None,
),
"explicit_comptime_composes_and_supplies_array_lengths": (
"""
size proc() usize { return 2 }
main proc() i16 {
amount :: 40
values [$(size())]i16 :: [$(amount + 1), $(1)]
return values[$(usize(0))] + values[1]
}
""", b"42\n", None,
),
"explicit_comptime_cannot_read_runtime_parameters": (
"""
select proc(value i16) i16 { return $(value + 1) }
main proc() i16 { return select(41) }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_aggregate_cannot_read_mutable_globals": (
"""
state i16 := 42
make proc() [1]i16 { return [state] }
main proc() i16 { return $(make())[0] }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_aggregate_keeps_narrow_overflow": (
"""
Counter :: struct { value i8 }
make proc() Counter {
result Counter := { value = 127 }
result.value = result.value + 1
return result
}
main proc() i8 { return $(make()).value }
""", b"", b"integer arithmetic overflow",
),
"comptime_aggregate_rejects_pointer_escape": (
"""
Borrow :: struct { pointer @i16 }
make proc() Borrow {
value i16 :: 42
return Borrow { pointer = &value }
}
main proc() i16 { return $(make()).pointer^ }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_aggregate_materializes_readonly_byte_slices": (
"""
make proc() [1][]u8 { return ["borrowed"] }
main proc() usize { return $(make())[0].len }
""", b"8\n", None,
),
"comptime_byte_slices_preserve_subviews_and_zero_sentinel": (
"""
subview proc() []u8 { return "unused42ignored"[6..8] }
terminated proc() [;0]u8 { return "unused42"[6..;0] }
main proc() [5]u8 {
plain :: $(subview())
zero [;0]u8 :: $(terminated())
return [plain[0], plain[1], zero[0], zero[1], zero.ptr[zero.len]]
}
""", b"[52, 50, 52, 50, 0]\n", None,
),
"comptime_byte_slices_own_filled_local_arrays": (
"""
make proc(seed u8) []u8 {
values [3]mut u8 := undefined
for (0..usize(3)) |index| values[index] = seed + u8(index)
copy := values
values[0] = 99
return copy[1..]
}
main proc() [4]u8 {
first :: $(make(40))
second :: $(make(10))
return [first[0], first[1], second[0], second[1]]
}
""", b"[41, 42, 11, 12]\n", None,
),
"comptime_byte_slices_materialize_immutable_globals_and_raw_fields": (
"""
bytes [4]u8 :: [9, 40, 2, 8]
Views :: struct { rows [2][]u8 }
make proc() Views { return { rows = [bytes[1..3], bytes[2..3]] } }
main proc() [3]u8 {
views :: $(make())
return [views.rows[0][0], views.rows[0][1], views.rows[1][0]]
}
""", b"[40, 2, 2]\n", None,
),
"comptime_byte_slices_preserve_nested_optional_tagged_and_fallible_channels": (
"""
Failure :: struct { text []u8 }
Choice :: union(enum) { data struct { rows [2]?[]u8 }, empty void }
Packet :: struct { choice ?Choice, result []u8 ! Failure }
make proc(fail bool) Packet {
values [2]mut u8 := [40, 2]
result []u8 ! Failure := values[..]
if (fail) result = Failure { text = values[1..] }
return {
choice = Choice { data = { rows = [values[..1], null] } },
result = result,
}
}
main proc() [4]u8 {
good :: $(make(false))
bad :: $(make(true))
choice :: good.choice?
if (choice.data.rows[1] != null) return [0, 0, 0, 0]
success :: good.result catch ""
failure :: bad.result catch |err| err.text
return [choice.data.rows[0]?[0], success[0], success[1], failure[0]]
}
""", b"[40, 40, 2, 2]\n", None,
),
"comptime_byte_slices_normalize_generic_cache_content": (
"""
make proc() []u8 {
values [2]mut u8 := [40, 2]
return values[..]
}
same proc() []u8 { return "(\\x28\\x02)"[1..3] }
other proc() []u8 { return "\\x28\\x03" }
Token proc($bytes []u8) type { return struct {} }
score proc($bytes []u8) u8 { return bytes[0] + bytes[1] }
main proc() u8 {
if (Token(make()) != Token(same())) return 0
if (Token(make()) != Token("\\x28\\x02")) return 0
if (Token(make()) == Token(other())) return 0
return score(make())
}
""", b"42\n", None,
),
"comptime_byte_slices_supply_generated_defaults": (
"""
make proc() []u8 {
values [2]mut u8 := [40, 2]
return values[..]
}
Generated proc() type {
return struct_type!(.auto, ["bytes"], [[]u8], [make()])
}
main proc() u8 {
value Generated() :: {}
return value.bytes[0] + value.bytes[1]
}
""", b"42\n", None,
),
"comptime_byte_slices_preserve_nul_high_bytes_and_empty_views": (
r"""
make proc() []u8 { return "!\x00\x80\xff?"[1..4] }
empty proc() []u8 { return "ignored"[3..3] }
zero proc() [;0]u8 { return ""[..;0] }
main proc() [6]usize {
bytes :: $(make())
plain :: $(empty())
terminated :: $(zero())
return [usize(bytes[0]), usize(bytes[1]), usize(bytes[2]),
plain.len, terminated.len, usize(terminated.ptr[0])]
}
""", b"[0, 128, 255, 0, 0, 0]\n", None,
),
"comptime_byte_slices_reject_uninitialized_source_bytes": (
"""
make proc() []u8 {
values [2]mut u8 := undefined
values[0] = 42
return values[..]
}
main proc() usize { return $(make()).len }
""", b"", b"local value was read before initialization",
),
"comptime_byte_slices_ignore_unobserved_uninitialized_bytes": (
"""
make proc() []u8 {
values [3]mut u8 := undefined
values[1] = 42
return values[1..2]
}
main proc() u8 { return $(make())[0] }
""", b"42\n", None,
),
"comptime_byte_slices_reject_invalid_ranges": (
"""
make proc() []u8 {
values [1]u8 :: [42]
return values[..2]
}
main proc() usize { return $(make()).len }
""", b"", b"slice",
),
"comptime_byte_slices_reject_oversized_pointer_views_before_allocation": (
"""
make proc() []u8 {
values [1]u8 :: [42]
return values.ptr[..maxval!(usize)]
}
main proc() usize { return $(make()).len }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_byte_slices_recheck_zero_sentinel_after_mutation": (
"""
make proc() [;0]u8 {
values [2]mut u8 := [42, 0]
view [;0]u8 :: values[..1;0]
values[1] = 7
return view
}
main proc() usize { return $(make()).len }
""", b"", b"sentinel",
),
"comptime_aggregate_rejects_mutable_byte_slice_escape": (
"""
make proc() [1][]mut u8 {
values [1]mut u8 := [42]
return [values[..]]
}
main proc() usize { return $(make())[0].len }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_aggregate_rejects_nonbyte_slice_escape": (
"""
make proc() []i16 {
values [1]i16 :: [42]
return values[..]
}
main proc() usize { return $(make()).len }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_aggregate_rejects_nominal_byte_slice_escape": (
"""
Byte :: distinct u8
make proc() []Byte {
values [1]Byte :: [42]
return values[..]
}
main proc() usize { return $(make()).len }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_nonzero_sentinel_byte_slices_own_subviews": (
"""
make proc() [;255]u8 {
values [5]mut u8 := [9, 40, 0, 2, 255]
return values[1..4;255]
}
empty proc() [;128]u8 {
values [1]u8 :: [128]
return values[..0;128]
}
main proc() usize {
value :: $(make())
zero :: $(empty())
if (value.len != 3 or value[1] != 0 or value.ptr[3] != 255) return 1
if (zero.len != 0 or zero.ptr[0] != 128) return 2
return usize(value[0]) + usize(value[2])
}
""", b"42\n", None,
),
"comptime_nonzero_sentinel_byte_slices_normalize_cache_and_defaults": (
"""
make proc(padded bool) [;7]u8 {
if (padded) {
prefixed [4]u8 :: [9, 40, 2, 7]
return prefixed[1..3;7]
}
values [3]u8 :: [40, 2, 7]
return values[..2;7]
}
Box proc($bytes [;7]u8) type { return struct { bytes [;7]u8 = bytes } }
main proc() u8 {
a Box(make(false)) :: {}
b Box(make(true)) :: a
direct Box("!(\\x02\\x07"[1..3;7]) :: b
if (direct.bytes.len != 2 or direct.bytes.ptr[2] != 7) return 0
return direct.bytes[0] + direct.bytes[1]
}
""", b"42\n", None,
),
"comptime_nonzero_sentinel_byte_slices_cross_nested_channels": (
"""
View :: struct { rows [1]??[;9]u8 }
Choice :: union(enum) { view View, empty void }
Failure :: struct { bytes [;9]u8 }
make proc() [;9]u8 {
values [3]u8 :: [40, 2, 9]
return values[..2;9]
}
choice proc() Choice { return .view { rows = [some!(some!(make()))] } }
success proc() View ! Failure { return { rows = [some!(some!(make()))] } }
failure proc() View ! Failure { return Failure { bytes = make() } }
main proc() usize {
value :: $(choice())
good :: $(success()) catch { return 1 }
bad :: $(failure()) catch |err| {
match value {
.view |view|: {
bytes :: view.rows[0]??
if (bytes.ptr[2] != 9 or good.rows[0]??.ptr[2] != 9) return 2
return usize(bytes[0]) + usize(err.bytes[1])
}
.empty: return 3
}
}
return bad.rows.len
}
""", b"42\n", None,
),
"inline_for_materializes_nonzero_sentinel_byte_slices": (
"""
make proc() [1][;1]u8 {
bytes [2]u8 :: [42, 1]
return [bytes[..1;1]]
}
main proc() u8 {
inline for make() |bytes| {
if (bytes.ptr[1] != 1) return 0
return bytes[0]
}
return 0
}
""", b"42\n", None,
),
"comptime_nonzero_sentinel_byte_slices_recheck_mutated_sentinel": (
"""
make proc() [;255]u8 {
values [2]mut u8 := [42, 255]
view [;255]u8 :: values[..1;255]
values[1] = 0
return view
}
main proc() usize { return $(make()).len }
""", b"", b"sentinel",
),
"comptime_nonzero_sentinel_byte_slices_reject_uninitialized_sentinel": (
"""
make proc() [;7]u8 {
values [2]mut u8 := [42, 7]
view [;7]u8 :: values[..1;7]
other [2]mut u8 := undefined
other[0] = 42
values = other
return view
}
main proc() usize { return $(make()).len }
""", b"", b"before initialization",
),
"comptime_nonzero_sentinel_byte_slices_reject_out_of_bounds_sentinel": (
"""
make proc() [;7]u8 {
values [1]u8 :: [42]
return values.ptr[..1;7]
}
main proc() usize { return $(make()).len }
""", b"", b"bounds",
),
"comptime_nonzero_sentinel_byte_slices_reject_mutable_escape": (
"""
make proc() [;7]mut u8 {
values [2]mut u8 := [42, 7]
return values[..1;7]
}
main proc() usize { return $(make()).len }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_tagged_union_preserves_tags_and_nested_raw_payloads": (
"""
Tag :: enum(i16) { number = -7, empty = 12, zero = 41, payload = 90 }
Empty :: struct {}
Payload :: struct { rows [2]struct { values [2]i16 }, text string }
Choice :: union(Tag) { payload Payload, empty void, zero Empty, number i16 }
make proc() Choice {
return .payload { rows = [{ values = [10, 20] }, { values = [4, 6] }], text = "ok" }
}
numeric proc() Choice { return .number{42} }
empty proc() Choice { return .empty }
zero proc() Choice { return .zero{} }
score proc(value Choice) i16 {
return match value {
.number |number|: number,
.payload |payload|: (
payload.rows[0].values[0] + payload.rows[0].values[1]
+ payload.rows[1].values[0] + payload.rows[1].values[1] + i16(payload.text.len)
),
.empty: 3,
.zero: 5,
}
}
main proc() [5]i16 {
value :: $(make())
return [score(value), value.payload.rows[1].values[1], score($(numeric())),
score($(empty())), score($(zero()))]
}
""", b"[42, 6, 42, 3, 5]\n", None,
),
"comptime_tagged_union_value_parameters_and_cache_identity": (
"""
Choice :: union(enum) { left i16, right i16 }
make proc() Choice { return .left{2} }
Fixed proc($choice Choice) type {
return struct { values [usize(choice.left)]i16 }
}
Token proc($choice Choice) type { return struct {} }
score proc($choice Choice) i16 {
return match choice { .left |value|: value, .right |value|: value + 1 }
}
main proc() i16 {
first Fixed(make()) :: { values = [20, 20] }
same Fixed(Choice { left = 2 }) :: first
if (Token(make()) != Token(Choice { left = 2 })) return 0
if (Token(make()) == Token(Choice { right = 2 })) return 0
if (Token(make()) == Token(Choice { left = 3 })) return 0
return same.values[0] + same.values[1] + score(make())
}
""", b"42\n", None,
),
"comptime_fallible_nested_storage_preserves_both_channels": (
"""
Error :: enum { failed }
Storage :: struct { values [2](i16 ! Error), text string ! Error }
make proc() Storage { return { values = [40, .failed], text = "ok" } }
main proc() i16 {
storage :: $(make())
text :: storage.text catch ""
return (storage.values[0] catch 0) + (storage.values[1] catch i16(text.len))
}
""", b"42\n", None,
),
"comptime_fallible_materializes_composed_and_payload_errors": (
"""
Missing :: enum { missing }
Detail :: union(enum) { failed struct { rows [2]i16, text string }, empty void }
Failure :: struct { code i16 }
missing proc() i16 ! (Missing | Detail) { return .missing }
detail proc() i16 ! (Missing | Detail) {
return .failed { rows = [20, 20], text = "ok" }
}
record proc() i16 ! Failure { return Failure { code = 42 } }
read proc(value i16 ! (Missing | Detail)) i16 {
return value catch |err| match err {
.missing: 7,
.failed |payload|: payload.rows[0] + payload.rows[1] + i16(payload.text.len),
.empty: 0,
}
}
main proc() [3]i16 {
return [read($(missing())), read($(detail())), $(record()) catch |err| err.code]
}
""", b"[7, 42, 42]\n", None,
),
"comptime_fallible_value_parameters_type_inputs_and_cache_identity": (
"""
Error :: enum { failed, other }
good proc() i16 ! Error { return 2 }
bad proc() i16 ! Error { return .failed }
Fixed proc($result i16 ! Error) type {
return struct { values [usize(result catch 1)]i16 }
}
Token proc($result i16 ! Error) type { return struct {} }
score proc($result i16 ! Error) i16 { return result catch 40 }
main proc() i16 {
first Fixed(good()) :: { values = [20, 20] }
same Fixed(2) :: first
if (Token(good()) != Token(2) or Token(bad()) != Token(Error.failed)) return 0
if (Token(good()) == Token(3) or Token(bad()) == Token(Error.other)) return 0
if (Token(good()) == Token(bad())) return 0
return same.values[0] + same.values[1] + score(good())
}
""", b"42\n", None,
),
"comptime_fallible_void_success_and_error_channels": (
"""
Error :: enum { failed }
good proc() void ! Error {}
bad proc() void ! Error { return .failed }
score proc($result void ! Error) i16 {
result catch { return 2 }
return 40
}
main proc() i16 {
value i16 := 0
$(good()) catch { value = 100 }
$(bad()) catch { value = 2 }
return value + score(good()) + score(bad()) - 2
}
""", b"42\n", None,
),
"comptime_fallible_preserves_overlapping_channel_types": (
"""
Success :: enum { failed }
Error :: enum { failed }
Value :: struct { code i16 }
Failure :: struct { code i16 }
good proc() Success ! Error { return Success.failed }
bad proc() Success ! Error { return Error.failed }
good_record proc() Value ! Failure { return Value { code = 40 } }
bad_record proc() Value ! Failure { return Failure { code = 2 } }
enum_score proc() i16 {
value :: $(good()) catch { return -1 }
if (value != Success.failed) return -2
$(bad()) catch { return 42 }
return 0
}
main proc() [2]i16 {
left :: $(good_record()) catch Value { code = 0 }
right :: $(bad_record()) catch |err| Value { code = err.code }
return [enum_score(), left.code + right.code]
}
""", b"[42, 42]\n", None,
),
"comptime_tagged_union_projects_raw_nested_channels": (
"""
Error :: enum { failed }
Choice :: union(enum) {
data struct { maybe ?i16, result i16 ! Error }
pointer @i16
empty void
}
make proc() Choice { return .data { maybe = 40, result = .failed } }
absent proc() Choice { return .empty }
main proc() i16 {
value :: $(make())
empty :: $(absent())
match empty { .empty: {}, else: return 0 }
return value.data.maybe? + (value.data.result catch 2)
}
""", b"42\n", None,
),
"comptime_tagged_union_rejects_nonnull_pointer_payload_escape": (
"""
Choice :: union(enum) { pointer @i16, empty void }
make proc() Choice {
value i16 :: 42
return .pointer{&value}
}
main proc() i16 { return $(make()).pointer^ }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_fallible_rejects_nonnull_success_pointer_escape": (
"""
Error :: enum { failed }
make proc() @i16 ! Error {
value i16 :: 42
return &value
}
main proc() i16 { return ($(make()) catch null)^ }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_fallible_rejects_nonnull_error_pointer_escape": (
"""
Failure :: struct { pointer @i16 }
make proc() i16 ! Failure {
value i16 :: 42
return Failure { pointer = &value }
}
main proc() i16 { return $(make()) catch |err| err.pointer^ }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_preserves_scalar_and_ieee_bits": (
"""
Storage :: union { real f64, bits u64 }
make proc(bits u64) Storage { return Storage { bits = bits } }
main proc() bool {
one :: $(make(4607182418800017408))
zero :: $(make(9223372036854775808))
nan :: $(make(9221120237041090626))
return (
one.real == 1.0 and zero.bits == 9223372036854775808
and nan.bits == 9221120237041090626
)
}
""", b"true\n", None,
),
"comptime_untagged_union_owns_padding_tail_bytes_and_copies": (
"""
Pair :: struct { small u8, large u64 }
Storage :: union { small u8, rows [2]mut Pair, words [4]mut u64, bytes [32]u8 }
make proc(prefix u64) Storage {
value := Storage { words = [prefix, 40, maxval!(u64), 2] }
value.small = 9
return value
}
Token proc($value Storage) type { return struct {} }
main proc() [8]u64 {
if (Token(make(maxval!(u64))) == Token(make(9))) return [0, 0, 0, 0, 0, 0, 0, 0]
value := $(make(maxval!(u64)))
saved :: value
value.small = 0
value.rows[0].large = 99
other :: $(make(maxval!(u64)))
return [u64(saved.small), u64(saved.bytes[1]), u64(saved.bytes[7]),
saved.rows[0].large, u64(saved.bytes[17]), u64(saved.bytes[23]),
other.rows[1].large, value.rows[0].large]
}
""", b"[9, 255, 255, 40, 255, 255, 2, 99]\n", None,
),
"comptime_untagged_union_cache_identity_and_generated_defaults": (
"""
Produced proc() type { return union { small u16, words [2]mut u16, bits u32 } }
Storage :: alias Produced()
make proc(tail u16) Storage {
value := Storage { words = [0, tail] }
value.small = 40
return value
}
Token proc($value Storage) type { return struct {} }
Fixed proc($value Storage) type { return struct { values [usize(value.words[1])]i16 } }
score proc($value Storage) u16 { return value.small + value.words[1] }
Generated proc() type {
return struct_type!(.auto, ["value"], [Storage], [make(2)])
}
main proc() u16 {
if (Token(make(2)) != Token(Storage { bits = 131112 })) return 0
if (Token(make(2)) != Token(Storage { words = [40, 2] })) return 0
if (Token(make(2)) == Token(make(3))) return 0
first Fixed(make(2)) :: { values = [20, 20] }
same Fixed(Storage { words = [40, 2] }) :: first
generated Generated() :: {}
if (generated.value.words[1] != 2 or same.values[1] != 20) return 0
return score(make(2))
}
""", b"42\n", None,
),
"comptime_untagged_union_preserves_zero_size_and_nominal_members": (
"""
Number :: distinct u16
Kind :: enum(u16) { answer = 42 }
Storage :: union { number Number, kind Kind }
Empty :: union { bytes [0]u8, record struct {} }
make proc() Storage { return Storage { kind = .answer } }
empty proc() Empty { return Empty { bytes = [] } }
exact proc(value Storage) Number { return value.number }
main proc() u16 {
zero :: $(empty())
if (sizeof!(Empty) != 0 or zero.bytes.len != 0) return 0
return u16(exact($(make())))
}
""", b"42\n", None,
),
"comptime_untagged_union_nested_optional_tagged_and_fallible_channels": (
"""
Storage :: union { small u16, words [2]u16 }
Choice :: union(enum) { data Storage, empty void }
Failure :: struct { value Storage }
Packet :: struct {
maybe [2]?Storage
choice Choice
success Storage ! Failure
failure Storage ! Failure
}
make proc() Packet {
value Storage :: { words = [40, 2] }
return {
maybe = [value, null], choice = .data{value},
success = value, failure = Failure { value = value },
}
}
score proc(value Storage) u16 { return value.words[0] + value.words[1] }
main proc() [4]u16 {
packet :: $(make())
if (packet.maybe[1] != null) return [0, 0, 0, 0]
good :: packet.success catch Storage { small = 0 }
bad :: packet.failure catch |err| err.value
return [score(packet.maybe[0]?), score(packet.choice.data), score(good), score(bad)]
}
""", b"[42, 42, 42, 42]\n", None,
),
"comptime_untagged_union_rejects_source_pointer": (
"""
Storage :: union { bits u64, pointer @i16 }
make proc() Storage {
value i16 :: 42
return Storage { pointer = &value }
}
main proc() u64 { return $(make()).bits }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_rejects_inactive_pointer_layout": (
"""
Storage :: union { bits u64, pointer ?@i16 }
make proc() Storage { return Storage { bits = 0 } }
main proc() u64 { return $(make()).bits }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_rejects_inactive_callback_layout": (
"""
Storage :: union { bits u64, callback @proc(value i16) i16 }
make proc() Storage { return Storage { bits = 42 } }
main proc() u64 { return $(make()).bits }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_rejects_inactive_string_layout": (
"""
Storage :: union { bits [2]u64, text string }
make proc() Storage { return Storage { bits = [0, 0] } }
main proc() u64 { return $(make()).bits[0] }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_rejects_nested_inactive_slice_layout": (
"""
Storage :: union { bits [2]u64, rows [1]struct { bytes []u8 } }
make proc() Storage { return Storage { bits = [0, 0] } }
main proc() u64 { return $(make()).bits[0] }
""", b"", b"compile-time result cannot escape evaluation",
),
"comptime_untagged_union_rejects_uninitialized_tail_bytes": (
"""
Storage :: union { small u8, words [2]mut u64 }
make proc() Storage {
value Storage := undefined
value.small = 42
return value
}
main proc() u8 { return $(make()).small }
""", b"", b"read before initialization",
),
"comptime_untagged_union_rejects_uninitialized_padding_bytes": (
"""
Pair :: struct { small u8, large u64 }
Storage :: union { pair Pair, words [2]u64 }
make proc() Storage {
value Storage := undefined
value.pair.small = 1
value.pair.large = 42
return value
}
main proc() u64 { return $(make()).pair.large }
""", b"", b"read before initialization",
),
"comptime_float_bits_survive_aggregate_materialization": (
"""
Floats :: struct { zero f64, nan f64 }
make proc() Floats {
bits u64 :: 9221120237041090626
return Floats { zero = -0.0, nan = ptrcast!(@f64, &bits)^ }
}
main proc() bool {
values :: $(make())
return (
ptrcast!(@u64, &values.zero)^ == 9223372036854775808
and ptrcast!(@u64, &values.nan)^ == 9221120237041090626
)
}
""", b"true\n", None,
),
"comptime_calls_share_runtime_inference_loops_and_recursion": (
"""
length proc() usize {
result := 0
while (result < 2) result = result + 1
return result
}
factorial proc(count usize) usize {
if (count == 0) return 1
return count * factorial(count - 1)
}
sum proc(count usize) usize {
result := 0
for (0..count) |index| {
if (index == 1) continue
if (index == 4) break
result = result + index
}
return result
}
identity proc($T type, value T) T { return value }
Fixed proc($N usize) type { return struct { values [N]i16 } }
main proc() i16 {
first Fixed(identity(usize, length())) :: { values = [40, 2] }
same Fixed(factorial(3) - sum(6) + 1) :: first
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"comptime_call_string_result_owns_escaped_bytes": (
r"""
choose proc(take bool, text string) string {
if (take) return text
return "unused"
}
offset proc($text string, value i16) i16 { return value + i16(text.len) }
main proc() i16 { return offset(choose(true, "a\"\\\x00é"), 36) }
""", b"42\n", None,
),
"comptime_calls_preserve_checked_narrow_intermediates": (
"""
overflow proc(seed i8) i8 {
result := seed
result = result + 1
return result - 1
}
answer proc($N i8) i16 { return 42 }
main proc() i16 { return answer(overflow(127)) }
""", b"", b"integer arithmetic overflow",
),
"comptime_calls_preserve_unsigned_and_signed_boundaries": (
"""
unsigned proc(value u64) u64 { return value }
signed proc(value i64) i64 { return value }
answer proc($high u64, $low i64) i16 {
if (high == 18446744073709551615 and low == -9223372036854775808) return 42
return 0
}
main proc() i16 {
return answer(unsigned(18446744073709551615), signed(-9223372036854775808))
}
""", b"42\n", None,
),
"comptime_call_cannot_promote_runtime_parameter": (
"""
identity proc(value usize) usize { return value }
answer proc($N usize) i16 { return 42 }
runtime proc(value usize) i16 { return answer(identity(value)) }
main proc() i16 { return runtime(2) }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_call_cannot_read_mutable_global": (
"""
state usize := 2
read proc() usize { return state }
answer proc($N usize) i16 { return 42 }
main proc() i16 { return answer(read()) }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_call_cannot_mutate_runtime_storage": (
"""
state usize := 0
write proc() usize {
state = 2
return state
}
answer proc($N usize) i16 { return 42 }
main proc() i16 { return answer(write()) }
""", b"", b"generic argument must be a compile-time value",
),
"comptime_call_keeps_uninitialized_local_traps": (
"""
premature proc() usize {
before :: after
after :: 2
return before
}
answer proc($N usize) i16 { return 42 }
main proc() i16 { return answer(premature()) }
""", b"", b"local value was read before initialization",
),
"comptime_call_bounds_empty_loops": (
"""
forever proc() usize {
while true {}
return 2
}
answer proc($N usize) i16 { return 42 }
main proc() i16 { return answer(forever()) }
""", b"", b"compile-time execution exceeds",
),
"comptime_call_bounds_recursive_frames": (
"""
forever proc(value usize) usize { return forever(value) }
answer proc($N usize) i16 { return 42 }
main proc() i16 { return answer(forever(2)) }
""", b"", b"compile-time execution exceeds",
),
"comptime_call_foreign_execution_remains_a_source_trap": (
"""
getpid c_func() c_int
answer proc($N c_int) i16 { return 42 }
main proc() i16 { return answer(getpid()) }
""", b"", b"foreign function calls are unsupported",
),
"specialization_parameterless_type_producer_is_cached": (
"""
Token proc() type { return struct { value i16 } }
main proc() i16 {
first Token() :: { value = 42 }
second Token() :: first
return second.value
}
""", b"42\n", None,
),
"specialization_explicit_identity_independent_widths": (
"""
identity proc($T type, value T) T { return value }
main proc() i16 {
narrow u8 :: identity(u8, 40)
wide i16 :: identity(i16, 2)
return i16(narrow) + wide
}
""", b"42\n", None,
),
"specialization_inferred_identity_independent_widths": (
"""
identity proc($T type, value T) T { return value }
main proc() i16 {
narrow u8 :: 40
wide i16 :: 2
first u8 :: identity(narrow)
second i16 :: identity(wide)
return i16(first) + second
}
""", b"42\n", None,
),
"specialization_cached_nominal_type_through_aliases": (
"""
Box proc($T type) type { return struct { value T } }
Element :: alias i16
First :: Box(Element)
Second :: alias Box(i16)
read proc(value Box(i16)) i16 { return value.value }
main proc() i16 {
first First :: { value = 40 }
second Second :: first
repeated Box(i16) :: second
return read(repeated) + 2
}
""", b"42\n", None,
),
"specialization_different_type_arguments_remain_nominally_distinct": (
"""
Box proc($T type) type { return struct { value T } }
main proc() i16 {
signed Box(i16) :: { value = 42 }
unsigned Box(u16) :: signed
return i16(unsigned.value)
}
""", b"", b"incompatible value type",
),
"specialization_generated_record_and_mutable_array_storage": (
"""
Fixed proc($T type, $N usize) type {
return struct { values [N]mut T }
}
main proc() i16 {
fixed Fixed(i16, 2) := { values = [40, 0] }
fixed.values[1] = 2
copy Fixed(i16, 2) :: fixed
return copy.values[0] + copy.values[1]
}
""", b"42\n", None,
),
"specialization_infers_generated_record_type_and_length": (
"""
Fixed proc($T type, $N usize) type {
return struct { values [N]mut T }
}
first proc($T type, $N usize, value @Fixed(T, N)) T {
return value.values[0]
}
length proc($T type, $N usize, value @Fixed(T, N)) usize {
return N
}
main proc() i16 {
fixed Fixed(i16, 2) :: { values = [40, 1] }
return first(&fixed) + i16(length(&fixed))
}
""", b"42\n", None,
),
"specialization_infers_pointer_array_element_and_length": (
"""
endpoints proc($T type, $N usize, values @[N]T) T {
return values[0] + values[N - 1]
}
main proc() i16 {
values [2]i16 :: [40, 2]
return endpoints(&values)
}
""", b"42\n", None,
),
"specialization_nested_runtime_calls": (
"""
identity proc($T type, value T) T { return value }
forward proc($T type, value T) T { return identity(value) }
main proc() i16 { return forward(i16, 42) }
""", b"42\n", None,
),
"specialization_nested_generated_types": (
"""
Box proc($T type) type { return struct { value T } }
Wrapped proc($T type) type { return struct { box Box(T) } }
main proc() i16 {
wrapped Wrapped(i16) :: { box = Box(i16){ value = 42 } }
return wrapped.box.value
}
""", b"42\n", None,
),
"specialization_recursive_runtime_call_reuses_instance": (
"""
repeat proc($T type, value T, remaining usize) T {
if (remaining == 0) return value
return repeat(value, remaining - 1)
}
main proc() i16 { return repeat(i16, 42, 3) }
""", b"42\n", None,
),
"specialization_immutable_scalar_arguments_and_expressions": (
"""
base usize :: 1
Fixed proc($T type, $N usize) type {
return struct { values [N]mut T }
}
main proc() i16 {
count usize :: base + 1
fixed Fixed(i16, count) :: { values = [40, 2] }
same Fixed(i16, 2) :: fixed
return same.values[0] + same.values[1]
}
""", b"42\n", None,
),
"specialization_rejects_mutable_compile_time_argument": (
"""
value proc($N usize, result i16) i16 { return result }
main proc() i16 {
count usize := 2
return value(count, 42)
}
""", b"", b"generic argument must be a compile-time value",
),
"specialization_rejects_runtime_compile_time_argument": (
"""
value proc($N usize, result i16) i16 { return result }
runtime proc(count usize) i16 { return value(count, 42) }
main proc() i16 { return runtime(2) }
""", b"", b"generic argument must be a compile-time value",
),
"specialization_boolean_value_parameters": (
"""
choose proc($enabled bool, value i16) i16 {
if (enabled) return value
return value + 2
}
main proc() i16 {
enabled :: true
if (choose(enabled, 40) != 40) return 0
return choose(false, 40)
}
""", b"42\n", None,
),
"specialization_string_value_parameters": (
"""
offset proc($text string, value i16) i16 {
return value + i16(text.len)
}
main proc() i16 { return offset("ab", 40) }
""", b"42\n", None,
),
"specialization_callback_value_parameters": (
"""
increment proc(value i16) i16 { return value + 2 }
apply proc($T type, $callback proc(value T) T, value T) T {
return callback(value)
}
main proc() i16 { return apply(i16, increment, 40) }
""", b"42\n", None,
),
"specialization_type_producer_conditional_returns": (
"""
Choose proc($wide bool) type {
if (wide) return struct { value i64 }
return struct { value i16 }
}
main proc() i16 {
narrow Choose(false) :: { value = 40 }
wide Choose(true) :: { value = 2 }
return narrow.value + i16(wide.value)
}
""", b"42\n", None,
),
"specialization_type_producer_local_computed_storage_count": (
"""
Fixed proc($T type, $N usize) type {
count usize :: N + 1
return struct { values [count]mut T }
}
main proc() i16 {
fixed Fixed(i16, 1) := { values = [40, 0] }
fixed.values[1] = 2
return fixed.values[0] + fixed.values[1]
}
""", b"42\n", None,
),
"specialization_rejects_out_of_range_unused_value_argument": (
"""
ignore proc($N u8) i16 { return 42 }
main proc() i16 { return ignore(256) }
""", b"", b"numeric literal is outside",
),
"specialization_rejects_inconsistent_inferred_type": (
"""
first proc($T type, left T, right T) T { return left }
main proc() i16 {
left i16 :: 40
right u8 :: 2
return first(left, right)
}
""", b"", b"cannot infer consistent compile-time arguments",
),
"specialization_recursive_generated_record_pointer": (
"""
Node proc($T type) type {
return struct { value T, next ?@Node(T) }
}
main proc() i16 {
tail Node(i16) :: { value = 2, next = null }
head Node(i16) :: { value = 40, next = &tail }
if head.next |next| return head.value + next.value
return 0
}
""", b"42\n", None,
),
"specialization_phantom_type_arguments_remain_nominally_distinct": (
"""
Phantom proc($T type) type { return struct { value i16 } }
main proc() i16 {
first Phantom(i16) :: { value = 42 }
second Phantom(u8) :: first
return second.value
}
""", b"", b"incompatible value type",
),
"specialization_phantom_value_arguments_remain_nominally_distinct": (
"""
Tagged proc($N usize) type { return struct { value i16 } }
main proc() i16 {
first Tagged(1) :: { value = 42 }
second Tagged(2) :: first
return second.value
}
""", b"", b"incompatible value type",
),
"specialization_direct_array_type_return": (
"""
Array proc($T type, $N usize) type { return [N]T }
Row :: alias Array(i16, 2)
main proc() i16 {
row Row :: [40, 2]
same Array(i16, 2) :: row
return same[0] + same[1]
}
""", b"42\n", None,
),
"specialization_value_parameter_preserves_narrow_arithmetic": (
"""
add proc($N u8) i64 { return i64(N + 1) }
main proc() i64 { return add(255) }
""", b"", b"integer arithmetic overflow",
),
"specialization_optional_value_null_capture_is_safe": (
"""
read proc($value ?i16) i16 {
if value |present| return present
return 42
}
main proc() i16 { return read(null) }
""", b"42\n", None,
),
"specialization_optional_value_null_unwrap_traps": (
"""
read proc($value ?i16) i16 { return value? }
main proc() i16 { return read(null) }
""", b"", b"null",
),
"specialization_optional_value_present_literal_capture": (
"""
read proc($value ?i16) i16 {
if value |present| return present
return 0
}
main proc() i16 { return read(42) }
""", b"42\n", None,
),
"specialization_optional_callback_unwrap_and_call": (
"""
increment proc(value i16) i16 { return value + 2 }
invoke proc($callback ?proc(value i16) i16, value i16) i16 {
return callback?(value)
}
main proc() i16 { return invoke(increment, 40) }
""", b"42\n", None,
),
"specialization_optional_callback_capture_and_null_comparison": (
"""
increment proc(value i16) i16 { return value + 2 }
invoke proc($callback ?proc(value i16) i16, value i16) i16 {
if callback |present| return present(value)
if (callback == null) return value + 2
return 0
}
main proc() i16 {
if (invoke(increment, 40) != 42) return 0
return invoke(null, 40)
}
""", b"42\n", None,
),
"specialization_string_argument_preserves_slice_annotation": (
"""
length proc($text []u8) usize { return text.len }
main proc() i16 { return 40 + i16(length("ab")) }
""", b"42\n", None,
),
"specialization_cached_phantom_type_canonical_builtin_alias": (
"""
Phantom proc($T type) type { return struct { value i16 } }
Element :: alias i64
main proc() i16 {
first Phantom(int) :: { value = 42 }
second Phantom(i64) :: first
third Phantom(Element) :: second
return third.value
}
""", b"42\n", None,
),
"specialization_infers_type_through_type_producer_wrapper": (
"""
Box proc($T type) type { return struct { value T } }
Wrapped proc($T type) type { return Box(T) }
read proc($T type, value @Wrapped(T)) T { return value.value }
main proc() i16 {
value Wrapped(i16) :: { value = 42 }
return read(&value)
}
""", b"42\n", None,
),
"specialization_string_cache_uses_decoded_value": (
"""
Tag proc($text string) type { return struct { value i16 } }
main proc() i16 {
first Tag("a") :: { value = 42 }
second Tag("\\x61") :: first
return second.value
}
""", b"42\n", None,
),
"specialization_rejects_invalid_compile_time_comparison": (
"""
ignore proc($flag bool) i16 { return 42 }
main proc() i16 { return ignore(1 == true) }
""", b"", b"generic argument must be a compile-time value",
),
"specialization_contextual_literal_after_typed_argument": (
"""
first proc($T type, left T, right T) T { return left }
main proc() i16 {
value i16 :: 42
result i16 :: first(value, 0)
return result
}
""", b"42\n", None,
),
"specialization_contextual_literal_before_typed_argument": (
"""
first proc($T type, left T, right T) T { return left }
main proc() i16 {
value i16 :: 42
result i16 :: first(0, value)
return result + 42
}
""", b"42\n", None,
),
"specialization_contextual_nested_integer_literal_expressions": (
"""
first proc($T type, left T, right T) T { return left }
main proc() i16 {
value i16 :: 40
left i16 :: first(-(1 + 1), value)
right i16 :: first(value, (3 * 4) + 2)
return left + right + 4
}
""", b"42\n", None,
),
"specialization_contextual_literal_right_out_of_range": (
"""
first proc($T type, left T, right T) T { return left }
main proc() u8 {
value u8 :: 42
return first(value, 256)
}
""", b"", b"numeric literal is outside",
),
"specialization_contextual_literal_left_out_of_range": (
"""
first proc($T type, left T, right T) T { return left }
main proc() u8 {
value u8 :: 42
return first(256, value)
}
""", b"", b"numeric literal is outside",
),
"fallible_success_and_catch_short_circuit": (
"""
Error :: enum { failed }
good proc() i16 ! Error { return 42 }
bad_fallback proc() i16 { value i16 :: 32767
return value + 1 }
main proc() i16 { return good() catch bad_fallback() }
""", b"42\n", None,
),
"fallible_try_composed_errors_and_capture": (
"""
First :: enum { first }
Second :: enum { second }
leaf proc() i16 ! Second { return .second }
middle proc() i16 ! (First | Second) { return try leaf() }
main proc() i16 {
return middle() catch |err| match err {
.first: 0,
.second: 42,
}
}
""", b"42\n", None,
),
"fallible_matched_error_residual_return": (
"""
First :: enum { first }
Second :: enum { second }
broad proc() i16 ! (First | Second) { return .second }
narrow proc() i16 ! Second {
broad() catch |err| {
match err {
.first: return 0,
else: return err,
}
}
return 0
}
main proc() i16 { return narrow() catch 42 }
""", b"42\n", None,
),
"fallible_matched_tagged_error_residual_return": (
"""
Missing :: enum { missing }
Detail :: union(enum) { failed i16 }
broad proc() i16 ! (Missing | Detail) { return .failed{42} }
narrow proc() i16 ! Detail {
broad() catch |err| {
match err {
.missing: return 0,
else: return err,
}
}
return 0
}
main proc() i16 {
return narrow() catch |err| match err { .failed |code|: code }
}
""", b"42\n", None,
),
"fallible_storage_arrays_and_callbacks": (
"""
Error :: enum { failed }
Callback :: alias @proc(value i16) i16 ! Error
Box :: struct { callback Callback, result i16 ! Error }
maybe proc(value i16) i16 ! Error {
if (value == 0) return .failed
return value
}
main proc() i16 {
box Box :: { callback = maybe, result = 40 }
values [2](i16 ! Error) :: [box.result, .failed]
first :: values[0] catch 0
second :: values[1] catch 2
return box.callback(first + second) catch 0
}
""", b"42\n", None,
),
"fallible_struct_error_payload": (
"""
Failure :: struct { code i16 }
fail proc() i16 ! Failure { return Failure { code = 42 } }
main proc() i16 { return fail() catch |err| err.code }
""", b"42\n", None,
),
"fallible_tagged_error_payload": (
"""
Error :: union(enum) { failed i16, empty void }
fail proc() i16 ! Error { return .failed{42} }
main proc() i16 {
return fail() catch |err| match err {
.failed |code|: code,
.empty: 0,
}
}
""", b"42\n", None,
),
"fallible_composed_tagged_payload_propagation": (
"""
Missing :: enum { missing }
Detail :: union(enum) { failed i16, empty void }
leaf proc() i16 ! Detail { return .failed{42} }
forward proc() i16 ! (Missing | Detail) { return try leaf() }
main proc() i16 {
return forward() catch |err| match err {
.missing: 0,
.failed |code|: code,
.empty: 0,
}
}
""", b"42\n", None,
),
"fallible_terminal_catch_block": (
"""
Error :: enum { failed }
fail proc() i16 ! Error { return .failed }
main proc() i16 {
return fail() catch |err| {
if (err == Error.failed) return 42
return 0
}
}
""", b"42\n", None,
),
"fallible_void_catch_and_fallthrough": (
"""
Error :: enum { failed }
good proc(value @mut i16) void ! Error { value^ = 40 }
fail proc() void ! Error { return .failed }
main proc() i16 {
value i16 := 0
good(&value) catch { value = 0 }
fail() catch { value = value + 2 }
return value
}
""", b"42\n", None,
),
"cleanup_scope_lifo_and_live_values": (
"""
main proc() int {
value := 0
{
defer value = value * 10 + 2
defer value = value * 10 + 4
}
return value
}
""", b"42\n", None,
),
"cleanup_return_payload_before_mutation": (
"""
Pair :: struct { a i16, b i16 }
get proc() Pair {
value Pair := { a = 40, b = 2 }
defer value.a = 0
return value
}
main proc() i16 { value :: get()
return value.a + value.b }
""", b"42\n", None,
),
"cleanup_loop_exited_scopes": (
"""
main proc() int {
value := 0
for 0..4 |i| {
defer value = value + 1
if (i == 0) continue
{
defer value = value + 10
break
}
}
return value
}
""", b"12\n", None,
),
"cleanup_only_reached_registrations": (
"""
write proc(value @mut i64) void {
defer value^ = value^ + 40
if (true) return
defer value^ = 0
}
main proc() int { value := 2
write(&value)
return value }
""", b"42\n", None,
),
"cleanup_errdefer_capture_and_order": (
"""
Error :: enum { failed }
fail proc(value @mut i64) int ! Error {
defer value^ = value^ * 10 + 2
errdefer |err| if (err == Error.failed) value^ = value^ * 10 + 4
return .failed
}
main proc() int { value := 0
ignored :: fail(&value) catch 0
return value + ignored }
""", b"42\n", None,
),
"cleanup_errdefer_skip_on_success_and_scope_exit": (
"""
Error :: enum { failed }
good proc(value @mut i64) int ! Error {
errdefer value^ = 0
{ errdefer value^ = 0 }
defer value^ = value^ + 2
return 1
}
main proc() int { value := 40
ignored :: good(&value) catch 0
return value }
""", b"42\n", None,
),
"cleanup_try_propagation": (
"""
Error :: enum { failed }
leaf proc() void ! Error { return .failed }
outer proc(value @mut i64) void ! Error {
defer value^ = value^ + 2
errdefer value^ = value^ + 40
try leaf()
value^ = 0
}
main proc() int { value := 0
outer(&value) catch {}
return value }
""", b"42\n", None,
),
"cleanup_direct_fallible_return_and_expired_scope": (
"""
First :: enum { first }
Second :: enum { second }
leaf proc() i16 ! Second { return .second }
forward proc(value @mut i64) i16 ! (First | Second) {
{ errdefer value^ = 0 }
errdefer value^ = value^ + 40
defer value^ = value^ + 2
return leaf()
}
main proc() int { value := 0
ignored :: forward(&value) catch 0
return value }
""", b"42\n", None,
),
"fallible_aggregate_success_copy": (
"""
Error :: enum { failed }
Pair :: struct { left i16, right i16 }
read proc() Pair ! Error {
value Pair := { left = 40, right = 2 }
defer value.left = 0
return value
}
main proc() i16 {
value :: read() catch Pair { left = 0, right = 0 }
return value.left + value.right
}
""", b"42\n", None,
),
"fallible_borrowed_slice_success": (
"""
Error :: enum { failed }
borrow proc(values []mut i16) []mut i16 ! Error { return values }
main proc() i16 {
values [2]mut i16 := [40, 2]
view :: borrow(values[..]) catch &[]
view[0] = view[0] + view[1]
return values[0]
}
""", b"42\n", None,
),
"fallible_optional_pointer_success": (
"""
Error :: enum { failed }
borrow proc(value @mut i16) ?@mut i16 ! Error { return value }
main proc() i16 {
value i16 := 40
pointer :: borrow(&value) catch null
if pointer |present| present^ = present^ + 2
return value
}
""", b"42\n", None,
),
"fallible_trap_is_not_caught": (
"""
Error :: enum { failed }
bad proc() int ! Error { value :: [1]
return value[2] }
main proc() int { return bad() catch 42 }
""", b"", b"index out of bounds",
),
"fallible_try_requires_channel": (
"main proc() int { return try 42 }", b"", b"",
),
"fallible_incompatible_propagation": (
"""
First :: enum { first }
Second :: enum { second }
leaf proc() int ! First { return .first }
bad proc() int ! Second { return try leaf() }
main proc() int { return bad() catch 42 }
""", b"", b"",
),
"cleanup_return_rejected": (
"main proc() int { defer return 0\nreturn 42 }", b"", b"",
),
"cleanup_errdefer_requires_fallible_function": (
"main proc() int { errdefer main()\nreturn 42 }", b"", b"",
),
"slice_mutation_alias_calls": (
"""
update proc(values []mut i16) []mut i16 {
values[1] = values[0] + 2
return values[1..]
}
main proc() i16 {
values [4]mut i16 := [0, 40, 0, 0]
view :: update(values[1..3])
copy :: view
copy[0] = copy[0] + 1
return values[2] - i16(view.len)
}
""", b"42\n", None,
),
"slice_empty_one_past_and_pointer_identity": (
"""
main proc() bool {
values [2]mut i16 := [40, 2]
all :: values[..]
empty :: all[2..2]
return empty.len == 0 and empty.ptr == all.ptr + 2
}
""", b"true\n", None,
),
"slice_nested_record_storage": (
"""
Row :: struct { values []mut i16 }
identity proc(row Row) Row { return row }
main proc() i16 {
values [2]mut i16 := [40, 2]
rows [1]Row :: [{ values = values[..] }]
selected :: identity(rows[0])
selected.values[0] = selected.values[0] + selected.values[1]
return values[0]
}
""", b"42\n", None,
),
"slice_empty_mutable_literal": (
"main proc() usize { values []mut i16 :: &[]\nreturn values.len }",
b"0\n", None,
),
"slice_string_sentinel": (
"""
read proc(text [;0]u8) u8 {
suffix :: text[1..;0]
return suffix.ptr[suffix.len] + suffix[0]
}
main proc() u8 { return read("!*") }
""", b"42\n", None,
),
"slice_checked_sentinel": (
"""
main proc() u8 {
values [3]mut u8 := [40, 2, 0]
pointer *mut u8 :: &values[0]
text [;0]mut u8 :: pointer[..2;0]
text[0] = text[0] + text[1]
plain []u8 :: text
return plain[0]
}
""", b"42\n", None,
),
"slice_reversed_bounds": (
"main proc() usize { a :: [1, 2]\nreturn a[2..1].len }",
b"", b"slice",
),
"slice_excessive_bounds": (
"main proc() usize { a :: [1, 2]\nreturn a[..3].len }",
b"", b"slice",
),
"slice_index_at_length": (
"main proc() i64 { a :: [40, 2]\ns :: a[..]\nreturn s[s.len] }",
b"", b"slice",
),
"slice_sentinel_mismatch": (
"main proc() usize { a :: [1, 2, 3]\nreturn a[..2;0].len }",
b"", b"sentinel",
),
"slice_readonly_write_rejected": (
"main proc() int { a :: [40, 2]\ns :: a[..]\ns[0] = 42\nreturn 42 }",
b"", b"writable",
),
"optional_values_storage_calls": (
"""
Box :: struct { value ?i16 }
choose proc(value ?i16) ?i16 { return value }
main proc() i16 {
box Box := { value = 40 }
options [2]mut ?i16 := [null, 2]
options[0] = choose(box.value)
return options[0]? + options[1]?
}
""", b"42\n", None,
),
"optional_capture_and_null_transition": (
"""
main proc() i16 {
value ?i16 := 40
total i16 := 0
while value |payload| {
total = total + payload
value = null
continue
}
if value |unused| return unused
if (value != null) return 0
value = 2
if value |payload| return total + payload
return 0
}
""", b"42\n", None,
),
"optional_pointer_identity_and_mutation": (
"""
main proc() i16 {
value i16 := 40
pointer ?@mut i16 := &value
if pointer |present| present^ = present^ + 2
readonly ?@i16 :: pointer
if (readonly == null) return 0
return readonly?^
}
""", b"42\n", None,
),
"optional_null_unwrap": (
"main proc() i16 { value ?i16 :: null\nreturn value? }",
b"", b"null",
),
"optional_untaken_unwrap": (
"main proc() i16 { value ?i16 :: null\nif (false) return value?\nreturn 42 }",
b"42\n", None,
),
"memory_layout_padded_aggregates": (
"""
Padded :: struct { tag u8, value u64 }
Empty :: struct {}
main proc() bool {
return (
sizeof!(Padded) == 16 and alignof!(Padded) == 8
and sizeof!([3]Padded) == 48 and sizeof!([]u8) == 16
and sizeof!(?@i16) == 8 and sizeof!(Empty) == 0
)
}
""", b"true\n", None,
),
"memory_pointer_cast_byte_alias": (
"""
main proc() u16 {
value u16 := 40
bytes *mut u8 :: ptrcast!(&value)
bytes[0] = bytes[0] + 2
whole @mut u16 :: ptrcast!(bytes)
return whole^
}
""", b"42\n", None,
),
"memory_constcast_slice": (
"""
main proc() i16 {
values [2]mut i16 := [40, 2]
readonly []i16 :: values[..]
writable []mut i16 :: constcast!(readonly)
writable[0] = writable[0] + writable[1]
return values[0]
}
""", b"42\n", None,
),
"memory_typed_copy_and_set": (
"""
Pair :: struct { number i16, ready bool }
main proc() i16 {
source [2]Pair :: [{ number = 40, ready = true }, { number = 2, ready = false }]
target [2]mut Pair := [{ number = 0, ready = false }, { number = 0, ready = false }]
memcopy!(target[..], source[..])
saved :: target[0]
memset!(target[..], { number = 21, ready = true })
if (!saved.ready or !target[1].ready) return 0
return target[0].number + target[1].number
}
""", b"42\n", None,
),
"memory_copy_overlap": (
"main proc() int { a [3]mut i16 := [1, 2, 3]\nmemcopy!(a[1..], a[..2])\nreturn 42 }",
b"", b"overlap",
),
"memory_copy_length_mismatch": (
"main proc() int { a [3]mut i16 := [1, 2, 3]\nmemcopy!(a[..1], a[1..])\nreturn 42 }",
b"", b"slice",
),
"memory_empty_copy_and_set": (
"main proc() int { a [0]mut i16 := []\nmemcopy!(a[..], a[..])\nmemset!(a[..], 42)\nreturn 42 }",
b"42\n", None,
),
"optional_nested_presence": (
"main proc() i16 { value ??i16 :: 42\nreturn value?? }", b"42\n", None,
),
"optional_callback_capture_from_call": (
"""
increment proc(value i16) i16 { return value + 2 }
factory proc() ?@proc(value i16) i16 { return increment }
main proc() i16 {
if factory() |callback| return callback(40)
return 0
}
""", b"42\n", None,
),
"slice_recursive_record": (
"""
Node :: struct { value i16, children []Node }
main proc() i16 {
children [0]Node :: []
node Node :: { value = 42, children = children[..] }
return node.value + i16(node.children.len)
}
""", b"42\n", None,
),
"slice_full_width_sentinel": (
"""
main proc() usize {
values [2]u64 :: [42, 18446744073709551615]
sentinel [;18446744073709551615]u64 :: values[..1;18446744073709551615]
return sentinel.len
}
""", b"1\n", None,
),
"memory_pointer_cast_preserves_readonly": (
"main proc() int { value i16 :: 40\npointer *mut u8 :: ptrcast!(&value)\nreturn 42 }",
b"", b"operator requires",
),
"slice_sentinel_strengthening_rejected": (
"main proc() int { a :: [1, 0]\ns []i64 :: a[..1]\nt [;0]i64 :: s\nreturn 42 }",
b"", b"incompatible",
),
"slice_fixed_signed_index_rejected": (
"main proc() i64 { a :: [42]\ns :: a[..]\ni i16 :: 0\nreturn s[i] }",
b"", b"index",
),
"optional_nonoptional_capture_rejected": (
"main proc() int { if true |payload| return 1\nreturn 42 }",
b"", b"condition",
),
"memory_foreign_main_rejected": (
"main c_func() i16", b"", b"main must",
),
"memory_opaque_dereference_rejected": (
"main proc() int { value i16 := 42\npointer *mut anyopaque :: ptrcast!(&value)\ndiscard :: pointer^\nreturn 42 }",
b"", b"dereference",
),
"memory_opaque_index_rejected": (
"main proc() int { value i16 := 42\npointer *mut anyopaque :: ptrcast!(&value)\ndiscard :: pointer[0]\nreturn 42 }",
b"", b"indexing",
),
"memory_opaque_slice_rejected": (
"main proc() int { value i16 := 42\npointer *mut anyopaque :: ptrcast!(&value)\ndiscard :: pointer[..1]\nreturn 42 }",
b"", b"operator requires",
),
"memory_opaque_arithmetic_rejected": (
"main proc() int { value i16 := 42\npointer *mut anyopaque :: ptrcast!(&value)\ndiscard :: pointer + 1\nreturn 42 }",
b"", b"operator requires",
),
"slice_contextual_borrow_preserves_readonly": (
"main proc() i16 { values [1]i16 :: [40]\nview []mut i16 :: &values\nview[0] = 42\nreturn values[0] }",
b"", b"incompatible",
),
"slice_contextual_scalar_borrow_rejected": (
"main proc() i16 { value i16 := 42\nview []mut i16 :: &value\nreturn view[0] }",
b"", b"incompatible",
),
"slice_implicit_borrow_preserves_binding_mutability": (
"main proc() i16 { values [1]mut i16 :: [40]\nview []mut i16 :: values\nview[0] = 42\nreturn values[0] }",
b"", b"incompatible",
),
"callback_concrete_vtable": (
"""
VTable :: struct { run @proc(context @mut State, amount i16) i16 }
State :: struct { value i16, vtable @VTable }
add proc(context @mut State, amount i16) i16 {
context.value = context.value + amount
return context.value
}
table VTable :: { run = add }
main proc() i16 {
state State := { value = 40, vtable = &table }
return state.vtable.run(&state, 2)
}
""", b"42\n", None,
),
"callback_pass_return_store_replace": (
"""
Callback :: alias @proc(value i16) i16
Holder :: struct { run Callback }
increment proc(value i16) i16 { return value + 1 }
twice proc(value i16) i16 { return value + value }
choose proc(first Callback, second Callback, flag bool) Callback {
if (flag) return first
return second
}
apply proc(callback Callback, value i16) i16 { return callback(value) }
main proc() i16 {
callback @proc(n i16) i16 := increment
callback = twice
holder Holder := { run = increment }
holder.run = callback
callbacks [2]mut Callback := [increment, twice]
callbacks[0] = choose(holder.run, increment, true)
return apply(callbacks[0], 21)
}
""", b"42\n", None,
),
"callback_nested_aggregate_arguments_and_result": (
"""
Payload :: struct { values [2]i16, pointer @mut i16 }
Callback :: alias @proc(input Payload, rows [2][2]i16) Payload
transform proc(input Payload, rows [2][2]i16) Payload {
input.pointer^ = input.pointer^ + rows[1][0]
return { values = [input.values[0] + rows[0][1], rows[1][1]], pointer = input.pointer }
}
select proc(callback Callback) Callback { return callback }
main proc() [3]i16 {
value i16 := 40
callback Callback :: select(transform)
result :: callback({ values = [40, 0], pointer = &value }, [[0, 2], [2, 42]])
return [result.values[0], result.values[1], result.pointer^]
}
""", b"[42, 42, 42]\n", None,
),
"callback_storage_address_is_data_pointer": (
"""
Callback :: alias @proc(value i16) i16
increment proc(value i16) i16 { return value + 1 }
twice proc(value i16) i16 { return value + value }
replace proc(slot @mut Callback, callback Callback) void { slot^ = callback }
main proc() i16 {
callback Callback := increment
replace(&callback, twice)
return (&callback)^(21)
}
""", b"42\n", None,
),
"callback_structural_inline_aggregate_signature": (
"""
identity proc(value struct { values [2]i16, pointer @i16 }) struct { values [2]i16, pointer @i16 } {
return value
}
main proc() i16 {
number i16 :: 2
callback @proc(input struct { values [2]i16, pointer @i16 }) struct { values [2]i16, pointer @i16 } :: identity
result :: callback({ values = [40, 0], pointer = &number })
return result.values[0] + result.pointer^
}
""", b"42\n", None,
),
"callback_parameter_signature_mismatch": (
"wrong proc(value u16) i16 { return 42 }\nmain proc() i16 { callback @proc(value i16) i16 :: wrong\nreturn callback(1) }",
b"", b"incompatible value type",
),
"callback_result_signature_mismatch": (
"wrong proc(value i16) u16 { return 42 }\nmain proc() i16 { callback @proc(value i16) i16 :: wrong\nreturn callback(1) }",
b"", b"incompatible value type",
),
"callback_nested_signature_mismatch": (
"""
wrong proc(value struct { rows [2][2]u16 }) i16 { return 42 }
main proc() i16 {
callback @proc(value struct { rows [2][2]i16 }) i16 :: wrong
return 42
}
""", b"", b"incompatible value type",
),
"callback_pointer_mutability_signature_mismatch": (
"wrong proc(value @mut i16) i16 { return value^ }\nmain proc() i16 { callback @proc(value @i16) i16 :: wrong\nreturn 42 }",
b"", b"incompatible value type",
),
"callback_wrong_argument_type": (
"identity proc(value i16) i16 { return value }\nmain proc() i16 { callback @proc(value i16) i16 :: identity\nreturn callback(true) }",
b"", b"incompatible value type",
),
"callback_wrong_argument_count": (
"identity proc(value i16) i16 { return value }\nmain proc() i16 { callback @proc(value i16) i16 :: identity\nreturn callback() }",
b"", b"argument count does not match",
),
"callback_readonly_vtable_assignment": (
"""
VTable :: struct { run @proc(value i16) i16 }
identity proc(value i16) i16 { return value }
replace proc(table @VTable) void { table.run = identity }
main proc() i16 {
table VTable := { run = identity }
replace(&table)
return 42
}
""", b"", b"pointer assignment requires a mutable pointee",
),
"callback_readonly_array_assignment": (
"identity proc(value i16) i16 { return value }\nmain proc() i16 { callbacks [1]@proc(value i16) i16 := [identity]\ncallbacks[0] = identity\nreturn 42 }",
b"", b"indexed assignment requires a writable array element",
),
"callback_invalid_annotation_recovery": (
"bad proc(callback @proc(value void) i16) void {}\nmain proc() i16 { return 42 }",
b"42\n", b"void cannot be stored",
),
"callback_mutable_signature_rejected": (
"bad proc(callback @mut proc(value i16) i16) void {}\nmain proc() i16 { return 42 }",
b"42\n", b"pointer requires a supported concrete pointee type",
),
"callback_many_signature_rejected": (
"bad proc(callback *proc(value i16) i16) void {}\nmain proc() i16 { return 42 }",
b"42\n", b"pointer requires a supported concrete pointee type",
),
"pointer_assignment_evaluates_rhs_first_once": (
"""
Box :: struct { value i16, count i16 }
target proc(p @mut Box) @mut Box {
p.count = p.count + 1
return p
}
input proc(p @mut Box) i16 {
p.count = p.count + 10
return p.count
}
main proc() [2]i16 {
box Box := { value = 0, count = 0 }
target(&box).value = input(&box)
return [box.value, box.count]
}
""", b"[10, 11]\n", None,
),
"pointer_recursive_record_type": (
"""
Node :: struct { value i16, next @Node }
read_next proc(p @Node) i16 { return p.next.value }
main proc() i16 { return 42 }
""", b"42\n", None,
),
"pointer_many_dereference": (
"""
read proc(p *i16) i16 { return p^ }
main proc() i16 {
values [1]mut i16 := [42]
return read((&values).ptr)
}
""", b"42\n", None,
),
"pointer_many_from_array_element": (
"""
main proc() i16 {
values [3]mut i16 := [1, 2, 3]
pointer *mut i16 :: &values[0]
pointer[2] = 42
return values[2]
}
""", b"42\n", None,
),
"pointer_readonly_child_type_rejected": (
"read proc(p @u16) u16 { return p^ }\nmain proc() u16 { value i16 := 42\nreturn read(&value) }",
b"", b"incompatible value type",
),
"pointer_scalar_alias_across_calls": (
"""
identity proc(p @mut i16) @mut i16 { return p }
update proc(p @mut i16) void { p^ = p^ + 2 }
main proc() i16 {
value i16 := 40
pointer :: identity(&value)
update(pointer)
return value
}
""", b"42\n", None,
),
"pointer_readonly_parameter": (
"""
read proc(p @i16) i16 { return p^ }
main proc() i16 {
value i16 := 42
return read(&value)
}
""", b"42\n", None,
),
"pointer_record_alias_and_value_copy": (
"""
Point :: struct { x i16, y i16 }
set proc(p @mut Point) void { p.x = 40 }
main proc() i16 {
point Point := { x = 1, y = 2 }
pointer :: &point
copy :: pointer^
set(pointer)
if (copy.x != 1) return -1
return point.x + pointer.y
}
""", b"42\n", None,
),
"pointer_array_and_many_index": (
"""
update proc(p @mut [3]mut i16) void {
p[1] = p[0] + 2
values :: p.ptr
values[2] = values[1]
}
main proc() i16 {
values [3]mut i16 := [40, 0, 0]
update(&values)
if ((&values).len != 3) return -1
return values[2]
}
""", b"42\n", None,
),
"pointer_aggregate_copy_keeps_alias": (
"""
Holder :: struct { pointer @mut i16 }
identity proc(h Holder) Holder { return h }
main proc() i16 {
value i16 := 40
first :: Holder { pointer = &value }
second :: identity(first)
pointers [2]@mut i16 :: [first.pointer, second.pointer]
pointers[1]^ = pointers[0]^ + 2
return value
}
""", b"42\n", None,
),
"pointer_global_returned_from_callee": (
"""
value i16 :: 42
address proc() @i16 { return &value }
recurse proc(p @i16, n i16) i16 {
if (n == 0) return p^
return recurse(p, n - 1)
}
main proc() i16 { return recurse(address(), 20) }
""", b"42\n", None,
),
"pointer_location_identity": (
"""
Point :: struct { x i16, y i16 }
identity proc(p @mut i16) @mut i16 { return p }
main proc() bool {
point Point := { x = 40, y = 2 }
values [2]mut i16 := [40, 2]
first :: &point
second :: &point
return (
first == second
and identity(&point.x) == &point.x
and &point.x != &point.y
and (&values).ptr == (&values).ptr
)
}
""", b"true\n", None,
),
"pointer_union_roundtrip": (
"""
Storage :: union { pointer @mut i16, same @mut i16 }
main proc() i16 {
value i16 := 40
storage :: Storage { pointer = &value }
pointer :: storage.same
pointer^ = pointer^ + 2
return value
}
""", b"42\n", None,
),
"pointer_nested_array_aggregate": (
"""
Point :: struct { x i16, y i16 }
main proc() i16 {
values [2]mut Point := [Point { x = 40, y = 2 }, Point { x = 0, y = 0 }]
pointer :: (&values).ptr
pointer[1] = pointer[0]
pointer[0].x = 9
return values[1].x + values[1].y
}
""", b"42\n", None,
),
"pointer_to_pointer": (
"""
set proc(p @mut @mut i16) void { p^^ = 42 }
main proc() i16 {
value i16 := 0
pointer := &value
set(&pointer)
return value
}
""", b"42\n", None,
),
"pointer_repeated_address_in_loop": (
"""
main proc() i16 {
value i16 := 0
for 0..42 |i| {
pointer :: &value
pointer^ = i16(i) + 1
}
return value
}
""", b"42\n", None,
),
"pointer_zero_sized_array_elements": (
"""
Empty :: struct {}
main proc() bool {
values [2]mut Empty := [Empty {}, Empty {}]
pointer :: (&values).ptr
pointer[1] = pointer[0]
return (&values).len == 2
}
""", b"true\n", None,
),
"pointer_array_bounds_trap": (
"main proc() i16 { values [1]mut i16 := [42]\nreturn (&values)[1] }",
b"", b"index out of bounds",
),
"pointer_address_before_initialization": (
"main proc() i16 { pointer :: &value\nvalue i16 := 42\nreturn pointer^ }",
b"", b"read before initialization",
),
"pointer_constant_is_readonly": (
"main proc() i16 { value i16 :: 40\npointer :: &value\npointer^ = 42\nreturn value }",
b"", b"",
),
"pointer_readonly_parameter_write_rejected": (
"set proc(p @i16) void { p^ = 42 }\nmain proc() i16 { value i16 := 0\nset(&value)\nreturn value }",
b"", b"",
),
"pointer_array_readonly_elements": (
"main proc() i16 { values [1]i16 := [40]\npointer :: &values\npointer[0] = 42\nreturn values[0] }",
b"", b"",
),
"pointer_readonly_not_mutable_argument": (
"set proc(p @mut i16) void { p^ = 42 }\nmain proc() i16 { value i16 :: 0\nset(&value)\nreturn value }",
b"", b"incompatible value type",
),
"pointer_nonpointer_dereference_rejected": (
"main proc() i16 { value i16 :: 42\nreturn value^ }",
b"", b"dereference requires",
),
"pointer_void_pointee_rejected": (
"unused proc(p @void) void {}\nmain proc() int { return 42 }",
b"42\n", b"pointer requires",
),
"pointer_temporary_address_rejected": (
"main proc() i16 { pointer :: &(40 + 2)\nreturn pointer^ }",
b"", b"address-of requires",
),
"pointer_unused_invalid_path": (
"unused proc() int { return 42^ }\nmain proc() int { return 42 }",
b"42\n", b"dereference requires",
),
"pointer_addition_preserves_alias_and_mutability": (
"""
advance proc(p *mut i16, count usize) *mut i16 { return p + count }
main proc() [3]i16 {
values [3]mut i16 := [1, 2, 3]
pointer :: advance((&values).ptr, 1)
pointer^ = 40
(pointer + 1)^ = pointer^ + 2
return [values[0], values[1], values[2]]
}
""", b"[1, 40, 42]\n", None,
),
"pointer_addition_aggregate_stride_and_identity": (
"""
Point :: struct { x i16, y i64 }
main proc() bool {
values [3]mut Point := [
Point { x = 1, y = 2 }, Point { x = 3, y = 4 }, Point { x = 5, y = 6 },
]
pointer :: (&values).ptr
next :: pointer + (1 + 1)
next.y = 42
last *mut Point :: &values[2]
return (next == last and values[2].y == 42
and pointer + 3 == next + 1)
}
""", b"true\n", None,
),
"pointer_addition_evaluates_operands_once_in_order": (
"""
first proc(count @mut usize, values *mut i16) *mut i16 {
count^ = count^ + 1
return values
}
second proc(count @mut usize) usize {
previous :: count^
count^ = count^ + 1
return previous
}
main proc() [2]i16 {
count usize := 0
values [2]mut i16 := [1, 42]
pointer :: first(&count, (&values).ptr) + second(&count)
return [pointer^, i16(count)]
}
""", b"[42, 2]\n", None,
),
"pointer_addition_zero_sized_elements": (
"""
Empty :: struct {}
main proc() bool {
values [2]mut Empty := [Empty {}, Empty {}]
pointer :: (&values).ptr
return pointer + 2 == pointer
}
""", b"true\n", None,
),
"pointer_addition_requires_usize_offset": (
"main proc() i16 { values [2]mut i16 := [1, 42]\noffset i16 :: 1\nreturn ((&values).ptr + offset)^ }",
b"", b"",
),
"pointer_addition_single_pointer_rejected": (
"main proc() i16 { value i16 := 42\nreturn (&value + 1)^ }",
b"", b"",
),
"pointer_subtraction_rejected": (
"main proc() i16 { values [2]mut i16 := [1, 42]\nreturn ((&values).ptr - 1)^ }",
b"", b"",
),
"pointer_reversed_addition_rejected": (
"main proc() i16 { values [2]mut i16 := [1, 42]\nreturn (1 + (&values).ptr)^ }",
b"", b"",
),
"pointer_addition_preserves_readonly_pointee": (
"main proc() i16 { values [2]i16 := [1, 42]\npointer :: (&values).ptr + 1\npointer^ = 7\nreturn values[1] }",
b"", b"",
),
"pointer_addition_unused_error_recovers": (
"bad proc(p *i16) *i16 { return p + true }\nmain proc() i16 { return 42 }",
b"42\n", b"",
),
"match_float_ranges": (
"""
score proc(n f64) i16 {
return match n { (-1.5)..0.5: 1, 0.5..=2.5: 42, else: 0 }
}
main proc() [3]i16 { return [score(-1.0), score(2.5), score(3.0)] }
""", b"[1, 42, 0]\n", None,
),
"distinct_float_literal_context": (
"""
Amount :: distinct f64
main proc() f64 {
first Amount :: 1.5
second :: 0.5 + first
return f64(second + 40)
}
""", b"42\n", None,
),
"distinct_enum_construction": (
"E :: enum { a, b }\nD :: distinct E\nmain proc() bool { return D(E.a) == D(E.a) }",
b"true\n", None,
),
"union_aligned_record_payload": (
"""
Pair :: struct { a u8, b u64 }
U :: union { pair Pair, words [2]mut u64 }
main proc() [2]u64 {
value := U { words = [1, 42] }
value.pair.b = 99
copy :: value
value.words[1] = 7
return [u64(copy.pair.a), copy.pair.b]
}
""", b"[1, 99]\n", None,
),
"tagged_union_result": (
"C :: union(enum) { empty void, value struct { x u8, y bool } }\nmain proc() C { return .value { x = 42, y = true } }",
b"{{42, true}}\n", None,
),
"tagged_union_void_result": (
"C :: union(enum) { empty void, value u8 }\nmain proc() C { return .empty }",
b"{}\n", None,
),
"distinct_boolean_equality": (
"Flag :: distinct bool\nmain proc() bool { return Flag(true) == Flag(true) and bool(Flag(true)) and !bool(Flag(false)) }",
b"true\n", None,
),
"match_aggregate_result": (
"""
E :: enum { a, b }
Point :: struct { x i16 }
choose proc(e E) Point { return match e { .a: Point { x = 42 }, .b: Point { x = 9 } } }
main proc() i16 { return choose(.a).x }
""", b"42\n", None,
),
"enum_context_and_values": (
"""
Token :: enum(i16) { if = -2, else, return = 40 }
identity proc(t Token) Token { return t }
main proc() i16 {
values [2]Token :: [.if, Token.return]
if (identity(values[0]) == .if) return i16(values[1]) + 2
return 0
}
""", b"42\n", None,
),
"enum_unsigned_backing": (
"E :: enum(u64) { high = 18446744073709551615 }\nmain proc() u64 { return u64(E.high) }",
b"18446744073709551615\n", None,
),
"distinct_arithmetic_and_layers": (
"""
Id :: distinct u8
Wrapped :: distinct Id
Alias :: alias Id
identity proc(n Id) Id { return n }
main proc() u8 {
n Alias := identity(Alias(40))
n = n + 2
return u8(Id(Wrapped(n)))
}
""", b"42\n", None,
),
"distinct_aggregate_copy": (
"""
Point :: struct { x i16 }
Wrapped :: distinct Point
identity proc(w Wrapped) Wrapped { return w }
main proc() i16 {
p Point := { x = 42 }
w :: identity(Wrapped(p))
p.x = 9
copy :: Point(w)
return copy.x
}
""", b"42\n", None,
),
"alias_function_and_global_identity": (
"""
value i16 :: 41
add proc(n i16) i16 { return n + 1 }
invoke :: alias add
other :: alias value
main proc() i16 { return invoke(other) }
""", b"42\n", None,
),
"distinct_overflow": (
"Id :: distinct u8\nmain proc() Id { a Id :: 255\nreturn a + 1 }",
b"", b"integer arithmetic overflow",
),
"distinct_constructor_range": (
"Id :: distinct u8\nmain proc() Id { return Id(256) }",
b"", b"integer arithmetic overflow",
),
"distinct_implicit_rejected": (
"Id :: distinct u8\nmain proc() Id { n u8 :: 42\nreturn n }",
b"", b"return does not match",
),
"distinct_identity_rejected": (
"A :: distinct u8\nB :: distinct u8\nmain proc() A { return B(42) }",
b"", b"return does not match",
),
"union_scalar_overlay": (
"""
Bits :: union { integer u64, real f64 }
main proc() f64 {
b := Bits { integer = 4607182418800017408 }
copy :: b
b.real = 2.0
return copy.real + b.real
}
""", b"3\n", None,
),
"union_nested_layout_and_copy": (
"""
Pair :: struct { low u8, high u8 }
Bits :: union { pair Pair, integer u16 }
Box :: struct { values [2]mut Bits }
identity proc(b Box) Box { return b }
main proc() [3]u16 {
b Box := { values = [Bits { integer = 513 }, Bits { pair = { low = 3, high = 4 } }] }
saved :: identity(b)
b.values[0].pair.high = 9
return [saved.values[0].integer, saved.values[1].integer, b.values[0].integer]
}
""", b"[513, 1027, 2305]\n", None,
),
"tagged_union_match_copy_and_mutation": (
"""
Tag :: enum(i16) { empty = -1, number = 42, pair = 90 }
Choice :: union(Tag) { pair struct { x i16, y i16 = 2 }, number i16, empty void }
score proc(c Choice) i16 {
return match c {
.number |n|: n
.pair |p|: p.x + p.y
.empty: 0
}
}
main proc() [3]i16 {
a Choice := .pair { x = 40 }
b :: a
a.pair.x = 9
c Choice :: .number{42}
return [score(b), score(a), score(c)]
}
""", b"[42, 11, 42]\n", None,
),
"tagged_union_void_and_group_capture": (
"""
Choice :: union(enum) { left u8, right u8, empty void }
score proc(c Choice) u8 {
match c {
.left, .right |n|: return n
.empty: return 0
}
}
main proc() u8 { a Choice :: .empty
return score(Choice { right = 42 }) + score(a) }
""", b"42\n", None,
),
"tagged_union_inactive_read": (
"C :: union(enum) { a u8, b u8 }\nmain proc() u8 { c :: C { a = 42 }\nreturn c.b }",
b"", b"tagged union field is not active",
),
"tagged_union_inactive_write": (
"C :: union(enum) { a u8, b u8 }\nmain proc() u8 { c := C { a = 42 }\nc.b = 9\nreturn c.a }",
b"", b"tagged union field is not active",
),
"match_expression_context_and_laziness": (
"""
Kind :: enum { first, second }
poison i16 :: 32767 + 1
choose proc() Kind { return .second }
main proc() i16 {
result i16 :: match choose() { .first: poison, .second: 42 }
return result
}
""", b"42\n", None,
),
"match_scalar_ranges_and_loop_control": (
"""
main proc() i16 {
sum i16 := 0
for 0..10 |i| {
match i {
0..3: continue
3, 4: sum = sum + 1
5..=7: sum = sum + 10
else: break
}
}
return sum
}
""", b"32\n", None,
),
"match_boolean_exhaustive": (
"main proc() i16 { return match true { false: 1, true: 42 } }",
b"42\n", None,
),
"match_non_exhaustive": (
"E :: enum { a, b }\nmain proc() i16 { return match E.a { .a: 42 } }",
b"", b"match is not exhaustive",
),
"match_overlapping_range": (
"main proc() i16 { return match 3 { 0..=3: 1, 3..5: 2, else: 42 } }",
b"", b"overlapping match pattern",
),
"enum_invalid_value": (
"E :: enum(u8) { a = 256 }\nmain proc() E { return .a }",
b"", b"representable constant integer",
),
"enum_nominal_identity": (
"A :: enum { a }\nB :: enum { a }\nmain proc() A { return B.a }",
b"", b"return does not match",
),
"union_requires_one_member": (
"U :: union { a u8, b u8 }\nmain proc() U { return U { a = 1, b = 2 } }",
b"", b"exactly one member",
),
"record_defaults_and_copies": (
"""
Point :: struct { x i16, y i16 = 2 }
seed Point :: { x = 40 }
identity proc(p Point) Point { return p }
main proc() [3]i16 {
a := identity(seed)
b := a
a.x = 9
return [b.x + b.y, a.x, seed.x]
}
""", b"[42, 9, 40]\n", None,
),
"contextual_record_arguments": (
"""
Point :: struct { x u8, y u8 = 2 }
add proc(p Point) u8 { return p.x + p.y }
main proc() u8 { return add({ x = 40 }) }
""", b"42\n", None,
),
"nested_records_arrays_tuples": (
"""
Point :: struct { x i16, y i16 = 2 }
Box :: struct { points [2]mut Point, pair struct { u8, bool }, empty struct {} }
identity proc(b Box) Box { return b }
main proc() Box {
a Box := { points = [{ x = 1 }, { x = 40 }], pair = {255, true}, empty = {} }
b :: identity(a)
a.points[0].x = 9
a.pair.0 = 8
return b
}
""", b"{[{1, 2}, {40, 2}], {255, true}, {}}\n", None,
),
"anonymous_records_and_numeric_fields": (
"""
main proc() i64 {
a := { x = 40, pair = {{2, true}, false} }
b :: a
a.x = 1
return b.x + b.pair.0.0
}
""", b"42\n", None,
),
"record_temporary_fields_and_guards": (
"""
Point :: struct { x u8, y u8 = 2 }
make proc() Point { return { x = 40 } }
main proc() u8 {
flag :: { ready = true }
if flag.ready { return make().x + make().y }
return 0
}
""", b"42\n", None,
),
"zero_cell_records": (
"""
Empty :: struct {}
Box :: struct { values [3]Empty, empty Empty }
main proc() Box { return { values = [{}, {}, {}], empty = {} } }
""", b"{[{}, {}, {}], {}}\n", None,
),
"record_default_override": (
"""
Point :: struct { x i64 = 9223372036854775807 + 1 }
main proc() i64 { p :: Point { x = 42 }
return p.x }
""", b"42\n", None,
),
"record_default_trap": (
"""
Point :: struct { x i64 = 9223372036854775807 + 1 }
main proc() i64 { p :: Point {}
return p.x }
""", b"", b"integer arithmetic overflow",
),
"record_branchful_default": (
"""
Point :: struct { x bool = false and (9223372036854775807 + 1 == 0) }
main proc() bool { p :: Point {}
return !p.x }
""", b"true\n", None,
),
"record_explicit_evaluation_order": (
"""
cycle i64 :: cycle
Point :: struct { x i64, y i64 }
main proc() Point { return Point { y = 9223372036854775807 + 1, x = cycle } }
""", b"", b"integer arithmetic overflow",
),
"record_explicit_before_default": (
"""
cycle i64 :: cycle
Point :: struct { x i64 = cycle, y i64 }
main proc() Point { return Point { y = 9223372036854775807 + 1 } }
""", b"", b"integer arithmetic overflow",
),
"record_assignment_rhs_before_place": (
"""
Point :: struct { xs [1]mut i64 }
main proc() Point { p Point := { xs = [0] }
p.xs[1] = 9223372036854775807 + 1
return p }
""", b"", b"integer arithmetic overflow",
),
"record_reordered_structural_assignment": (
"main proc() int { a := { x = 1, y = 2 }\na = { y = 40, x = 2 }\nreturn a.x + a.y }",
b"42\n", None,
),
"record_local_type_and_loop": (
"""
main proc() i16 {
Point :: struct { x i16 }
p Point := { x = 0 }
for 0..100 |i| {
copy := p
copy.x = p.x + 1
p = copy
}
return p.x
}
""", b"100\n", None,
),
"record_function_field": (
"""
plus proc(n i64) i64 { return n + 1 }
minus proc(n i64) i64 { return n - 1 }
main proc() i64 { p := { f = plus }
p.f = minus
return p.f(43) }
""", b"42\n", None,
),
"record_nominal_mismatch": (
"A :: struct { x i64 }\nB :: struct { x i64 }\nmain proc() A { b :: B { x = 42 }\nreturn b }",
b"", b"",
),
"record_missing_field": (
"Point :: struct { x i64, y i64 }\nmain proc() Point { return { x = 42 } }", b"", b"",
),
"record_duplicate_field": (
"Point :: struct { x i64 }\nmain proc() Point { return { x = 1, x = 2 } }", b"", b"",
),
"record_unknown_field": (
"Point :: struct { x i64 }\nmain proc() Point { return { x = 1, z = 2 } }", b"", b"",
),
"record_wrong_field_type": (
"Point :: struct { x u8 }\nmain proc() Point { n u16 :: 42\nreturn { x = n } }", b"", b"",
),
"record_readonly_field": (
"Point :: struct { x i64 }\nmain proc() i64 { p :: Point { x = 1 }\np.x = 2\nreturn p.x }",
b"", b"",
),
"record_readonly_array_field": (
"Point :: struct { xs [1]i64 }\nmain proc() i64 { p Point := { xs = [1] }\np.xs[0] = 2\nreturn p.xs[0] }",
b"", b"",
),
"record_parameter_readonly": (
"Point :: struct { x i64 }\nmutate proc(p Point) i64 { p.x = 2\nreturn p.x }\nmain proc() i64 { return mutate({ x = 1 }) }",
b"", b"",
),
"record_recursive_layout": (
"Point :: struct { next Point }\nmain proc() int { return 42 }", b"42\n", b"",
),
"record_tuple_arity": (
"main proc() struct { i64, bool } { return {42,} }", b"", b"",
),
"record_unused_bad_body": (
"Point :: struct { x i64 }\nbad proc() Point { return { missing = 1 } }\nmain proc() i64 { return 42 }",
b"42\n", b"",
),
"record_field_bounds": (
"Point :: struct { xs [1]i64 }\nmain proc() i64 { p :: Point { xs = [42] }\nreturn p.xs[1] }",
b"", b"index out of bounds",
),
"record_type_not_value": (
"Point :: struct { x i64 }\nmain proc() i64 { Point\nreturn 42 }", b"", b"type name cannot",
),
"void": ("main proc() void {}", b"", None),
"signed_limits": (
"main proc() [2]i64 { return [-9223372036854775808, 9223372036854775807] }",
b"[-9223372036854775808, 9223372036854775807]\n", None,
),
"float_context": ("main proc() float { return 3 / 2 }", b"1.5\n", None),
"float_ieee": (
"""
main proc() bool {
nan :: 0.0 / 0.0
inf :: 1.0 / 0.0
return nan != nan and !(nan == nan) and !(nan < 0.0) and !(nan >= 0.0) and inf > 1.0
}
""", b"true\n", None,
),
"float_rounding": (
"main proc() f64 { return 9007199254740993.0 - 9007199254740992 }", b"0\n", None,
),
"strings": (r'main proc() string { return "a\0b\n\"\\" }', b'a\0b\n"\\\n', None),
"scalar_call_types": (
"""
nothing proc() void {}
twice proc(x f64) f64 { return x * 2 }
select proc(flag bool, left string, right string) string {
nothing()
if flag { return left }
return right
}
main proc() string { return select(twice(1.5) == 3.0, "yes", "no") }
""", b"yes\n", None,
),
"mutual_recursion": (
"""
even proc(n int) bool { if n == 0 { return true } return odd(n - 1) }
odd proc(n int) bool { if n == 0 { return false } return even(n - 1) }
main proc() bool { return even(20) and odd(19) }
""", b"true\n", None,
),
"function_values": (
"""
plus proc(n int) int { return n + 1 }
minus proc(n int) int { return n - 1 }
main proc() bool {
f := plus
f = minus
a :: [plus, f]
return a[0](41) == 42 and a[1](43) == 42
}
""", b"true\n", None,
),
"short_circuit": (
"""
cycle bool :: cycle
bad proc() bool { return 9223372036854775807 + 1 == 0 }
main proc() bool { return !(false and bad()) and (true or cycle) }
""", b"true\n", None,
),
"lazy_globals": (
"""
first :: identity(later)
later [2][2]string :: [["one", "two"], ["three", "four"]]
identity proc(a [2][2]string) [2][2]string { return a }
main proc() [2][2]string { return identity(identity(first)) }
""", b"[[one, two], [three, four]]\n", None,
),
"array_copies": (
"""
seed [2]mut [2]mut i64 :: [[1, 2], [3, 4]]
identity proc(a [2]mut [2]mut i64) [2]mut [2]mut i64 { return a }
main proc() [2]mut [2]mut i64 {
a := identity(seed)
b := a
(a[0])[1] = 99
a[1] = a[0]
return b
}
""", b"[[1, 2], [3, 4]]\n", None,
),
"zero_leaf_arrays": (
"""
identity proc(a [2][0]bool) [2][0]bool { return a }
main proc() [2][0]bool { return identity([[], []]) }
""", b"[[], []]\n", None,
),
"array_branchful_arguments": (
"""
identity proc(a [2]bool) [2]bool { return a }
pair proc(a [2]bool, b [2]bool) [2][2]bool { return [a, b] }
main proc() [2][2]bool {
return pair(identity([true or false, false and true]), identity([false or true, !false]))
}
""", b"[[true, false], [true, true]]\n", None,
),
"unsigned_max_range": (
"""
main proc() int {
end usize :: 18446744073709551615
start usize :: 18446744073709551614
count := 0
for start..=end |i| {
if (i < start) return 0
count = count + 1
continue
}
return count
}
""", b"2\n", None,
),
"unsigned_comparisons": (
"""
main proc() bool {
a usize :: 9223372036854775808
return a > 9223372036854775807 and a * 1 + 1 - 1 == a
}
""", b"true\n", None,
),
"signed_range_limits": (
"""
main proc() int {
maximum :: 9223372036854775807
count := 0
for maximum..=maximum |_| { count = count + 1 }
for 2..1 |_| { count = 0 }
for (-2)..0 |_| { count = count + 1 }
return count
}
""", b"3\n", None,
),
"loop_array_storage": (
"""
main proc() int {
n := 0
a [1]mut i64 := [0]
while n < 10000 {
row [1]mut i64 := [a[0]]
row[0] = row[0] + 1
a = row
n = n + 1
}
return a[0]
}
""", b"10000\n", None,
),
"forward_local": (
"main proc() int {\n before :: after\n after :: 42\n return before\n}",
b"", b"local value was read before initialization",
),
"forward_assignment": (
"main proc() int {\n after = 1\n after := 42\n return after\n}",
b"", b"local value was assigned before initialization",
),
"loop_local_reset": (
"""
main proc() int {
n := 0
while n < 2 {
n = n + 1
if (n == 2) return later[0]
later [1]i64 :: [42]
}
return 0
}
""", b"", b"local value was read before initialization",
),
"global_cycle": (
"a [1]i64 :: b\nb [1]i64 :: a\nmain proc() int { return a[0] }",
b"", b"global initialization cycle",
),
"bounds": (
"main proc() int {\n a :: [42]\n return a[1]\n}", b"", b"index out of bounds",
),
"empty_bounds": (
"main proc() int {\n a [0]i64 :: []\n return a[0]\n}", b"", b"index out of bounds",
),
"unsigned_bounds": (
"main proc() int {\n a [1]mut i64 := [1]\n a[18446744073709551615] = 2\n return 0\n}",
b"", b"index out of bounds",
),
"assignment_error_order": (
"main proc() int {\n a [0]mut i64 := []\n a[0] = 9223372036854775807 + 1\n return 0\n}",
b"", b"integer arithmetic overflow",
),
"signed_add_overflow": (
"main proc() int { return 9223372036854775807 + 1 }", b"", b"integer arithmetic overflow",
),
"signed_subtract_overflow": (
"main proc() int { return -9223372036854775808 - 1 }", b"", b"integer arithmetic overflow",
),
"signed_multiply_overflow": (
"main proc() int { return 9223372036854775807 * 2 }", b"", b"integer arithmetic overflow",
),
"signed_negate_overflow": (
"main proc() int { return -(-9223372036854775808) }", b"", b"integer arithmetic overflow",
),
"unsigned_subtract_overflow": (
"main proc() usize {\n zero usize :: 0\n return zero - 1\n}", b"", b"integer arithmetic overflow",
),
"unsigned_add_overflow": (
"main proc() usize { return 18446744073709551615 + 1 }", b"", b"integer arithmetic overflow",
),
"unsigned_multiply_overflow": (
"main proc() usize {\n max usize :: 18446744073709551615\n return max * 2\n}",
b"", b"integer arithmetic overflow",
),
"unused_errors": (
"bad proc() int { return absent }\nmain proc() int { return 42 }", b"42\n", b"unknown name",
),
"reached_source_error": (
"main proc() int { return absent }", b"", b"unknown name",
),
"missing_return": (
"main proc() int { if false { return 42 } }", b"", b"nonvoid function can finish",
),
"missing_entry": ("other proc() void {}", b"", b"program requires a main function"),
"invalid_unused_signature": (
"bad proc(a void) void {}\nmain proc() int { return 42 }", b"42\n", b"void cannot be stored",
),
"optional_compile_time_callbacks_preserve_source_identity": (
"""
first proc(value i16) i16 { return value }
second proc(value i16) i16 { return value + 2 }
invoke proc($callback proc(value i16) i16, value i16) i16 { return callback(value) }
choose proc($callback ?proc(value i16) i16, value i16) i16 {
if $(callback == null) return value + 3
else return invoke(callback?, value)
}
main proc() [3]i16 { return [choose(first, 42), choose(second, 40), choose(null, 39)] }
""", b"[42, 42, 42]\n", None,
),
"null_compile_time_callback_unwrap_traps": (
"""
invoke proc($callback proc() i16) i16 { return callback() }
choose proc($callback ?proc() i16) i16 { return invoke(callback?) }
main proc() i16 { return choose(null) }
""", b"", b"null optional",
),
"compile_error_reports_owned_computed_message": (
"""
explain proc() string { return "invalid \\"key\\"" }
fail proc($bad bool) i16 {
if (bad) compile_error!(explain())
return 42
}
main proc() i16 { return fail(true) }
""", b"", b'invalid "key"',
),
"compile_error_skips_unselected_generic_and_type_bodies": (
"""
choose proc($bad bool) i16 {
if (bad) compile_error!("wrong branch")
return 42
}
Storage proc(bad bool) type {
if (bad) compile_error!("wrong type branch")
return i16
}
main proc() Storage(false) { return choose(false) }
""", b"42\n", None,
),
"compile_error_type_execution_preserves_message": (
"""
Storage proc(bad bool) type {
if (bad) compile_error!("invalid generated storage")
return i16
}
main proc() Storage(true) { return 42 }
""", b"", b"invalid generated storage",
),
"compile_error_custom_diagnostics_survive_later_evaluation": (
"""
unused proc() void { compile_error!("retained message") }
compute proc() i16 { return 42 }
main proc() i16 { return $(compute()) }
""", b"42\n", b"error: retained message",
),
"compile_error_rejects_runtime_messages": (
"""
fail proc(message string) void { compile_error!(message) }
main proc() i16 { fail("not constant")\nreturn 42 }
""", b"", b"compile_error! requires one compile-time string argument",
),
"compile_error_rejects_wrong_arity": (
"main proc() i16 { compile_error!()\nreturn 42 }",
b"", b"compile_error! requires one compile-time string argument",
),
"type_execution_unreachable_is_selected_only": (
"""
Storage proc(bad bool) type {
if (bad) unreachable
return i16
}
main proc() Storage(false) { return 42 }
""", b"42\n", None,
),
"type_execution_unreachable_retains_source": (
"""
Storage proc() type {
unreachable
}
main proc() Storage() { return 42 }
""", b"", b":2:5:",
),
"rigid_slice_inference_preserves_borrowing_and_string_context": (
"""
Box proc($T type) type { return struct { value T } }
length proc($T type, box @Box(T), value T) usize { return box.value.len + value.len }
main proc() [3]usize {
box Box([]u8) :: { value = "ab" }
bytes [3]mut u8 := [1, 2, 3]
return [length(&box, bytes[..]), length(&box, "abc"), length(&box, bytes)]
}
""", b"[5, 5, 5]\n", None,
),
"rigid_slice_inference_rejects_readonly_weakening_reversal": (
"""
Box proc($T type) type { return struct { value T } }
write proc($T type, box @Box(T), value T) void { value[0] = 0 }
main proc() i16 {
bytes [1]mut u8 := [42]
box Box([]mut u8) :: { value = bytes[..] }
readonly []u8 :: bytes[..]
write(&box, readonly)
return 42
}
""", b"", b"",
),
"rigid_slice_inference_rejects_incompatible_elements": (
"""
Box proc($T type) type { return struct { value T } }
length proc($T type, box @Box(T), value T) usize { return value.len }
main proc() usize {
box Box([]u8) :: { value = "" }
words [1]i16 :: [42]
return length(&box, words[..])
}
""", b"", b"",
),
}
# Keep malformed schemas grouped: each must fail before generated storage is used.
for name, expression, diagnostic in (
(
"argument_count",
'struct_type!(.auto, ["value"], [i16])',
b"argument count",
),
(
"invalid_layout",
'struct_type!(.packed, ["value"], [i16], [null])',
b"layout",
),
(
"invalid_field_name",
'struct_type!(.auto, ["9value"], [i16], [null])',
b"generated field name",
),
(
"duplicate_field_name",
'struct_type!(.auto, ["value", "value"], [i16, i16], [null, null])',
b"specified more than once",
),
(
"named_record_collection",
'struct_type!(.auto, {name = "value"}, [i16], [null])',
b"compile-time value",
),
(
"unequal_collection_lengths",
'struct_type!(.auto, ["value", "bias"], [i16], [null, 2])',
b"length does not match",
),
(
"non_type_field",
'struct_type!(.auto, ["value"], [42], [null])',
b"record fields require a concrete value type",
),
(
"compile_time_only_field",
'struct_type!(.auto, ["value"], [type], [null])',
b"record fields require a concrete value type",
),
(
"wrong_typed_default",
'struct_type!(.auto, ["value"], [i16], [u8(2)])',
b"incompatible value type",
),
(
"out_of_range_default",
'struct_type!(.auto, ["value"], [i8], [128])',
b"outside its runtime type",
),
(
"empty_c_layout",
'struct_type!(.c, [], [], [])',
b"C-layout",
),
(
"non_c_field",
'struct_type!(.c, ["value"], [string], [null])',
b"C-layout",
),
(
"non_c_nested_record",
'struct_type!(.c, ["value"], [struct { value i16 }], [null])',
b"C-layout",
),
):
CASES[f"struct_type_rejects_{name}"] = (
f"""
Generated proc() type {{ return {expression} }}
main proc() i16 {{
value Generated() :: {{}}
return 42
}}
""", b"", diagnostic,
)
generated_field_count = 4097
CASES["struct_type_bounds_generated_field_construction"] = (
"Record :: struct_type!(.auto, ["
+ ", ".join(f'"field_{index}"' for index in range(generated_field_count))
+ "], [" + ", ".join(["i16"] * generated_field_count)
+ "], [" + ", ".join(["null"] * generated_field_count)
+ "])\nmain proc() i16 { value Record :: {}\nreturn 42 }\n",
b"", b"compile-time execution exceeds",
)
# Exercise each representation through storage, calls, ranges and checked updates.
for integer_type, bits, signed in (
("i8", 8, True), ("i16", 16, True), ("i32", 32, True),
("i64", 64, True), ("isize", 64, True),
("u8", 8, False), ("u16", 16, False), ("u32", 32, False),
("u64", 64, False), ("usize", 64, False),
):
minimum = -(1 << (bits - 1)) if signed else 0
maximum = (1 << (bits - int(signed))) - 1
CASES[f"{integer_type}_bitwise_boundaries"] = (
f"""
shift proc(value {integer_type}, count u64) [4]{integer_type} {{
return [value << count, value >> count, value <<| count, ~value]
}}
main proc() [8]{integer_type} {{
high :: shift(maxval!({integer_type}), {bits - 1})
huge :: shift_zero({integer_type}(0), maxval!(u64))
return [high[0], high[1], high[2], high[3],
{integer_type}(1) <<| maxval!(u64), huge,
minval!({integer_type}) <<| maxval!(u64),
minval!({integer_type}) >> u8({bits - 1})]
}}
shift_zero proc(value {integer_type}, count u64) {integer_type} {{ return value <<| count }}
""",
(f"[{- (1 << (bits - 1)) if signed else 1 << (bits - 1)}, "
f"{0 if signed else 1}, {maximum}, {minimum}, {maximum}, 0, {minimum}, "
f"{-1 if signed else 0}]\n").encode(),
None,
)
CASES[f"{integer_type}_limits_and_truncating_division"] = (
f"""
identity proc(value {integer_type}) {integer_type} {{ return value }}
main proc() [4]{integer_type} {{
return [identity(minval!({integer_type})), identity(maxval!({integer_type})),
divtrunc!(maxval!({integer_type}), 2), divtrunc!(minval!({integer_type}), 2)]
}}
""",
f"[{minimum}, {maximum}, {maximum // 2}, {-((-minimum) // 2) if minimum < 0 else 0}]\n".encode(),
None,
)
CASES[f"{integer_type}_storage"] = (
f"""
seed [2]mut {integer_type} :: [{minimum}, {maximum}]
identity proc(a [2]mut {integer_type}) [2]mut {integer_type} {{ return a }}
main proc() [2]mut {integer_type} {{
a := identity(seed)
b := a
a[0] = 1
return b
}}
""", f"[{minimum}, {maximum}]\n".encode(), None,
)
CASES[f"{integer_type}_inclusive_max"] = (
f"""
main proc() int {{
start {integer_type} :: {maximum - 1}
end {integer_type} :: {maximum}
count := 0
for start..=end |i| {{
if (i < start) return -1
count = count + 1
continue
}}
return count
}}
""", b"2\n", None,
)
for operation, left, right in (
("+", maximum, 1), ("-", minimum, 1), ("*", maximum, 2),
):
CASES[f"{integer_type}_overflow_{operation}"] = (
f"main proc() {integer_type} {{ a {integer_type} :: {left}\nreturn a {operation} {right} }}",
b"", b"integer arithmetic overflow",
)
CASES[f"{integer_type}_literal_range"] = (
f"main proc() {integer_type} {{ return {maximum + 1} }}",
b"", b"numeric literal is outside",
)
if signed:
CASES[f"{integer_type}_negate_min"] = (
f"main proc() {integer_type} {{ a {integer_type} :: {minimum}\nreturn -a }}",
b"", b"integer arithmetic overflow",
)
CASES.update({
"integer_casts": (
"""
identity proc(n u8) u8 { return n }
main proc() [4]i64 {
large u64 :: 18446744073709551615
small := identity(u8(i16(255)))
if (large != u64(18446744073709551615)) return [0, 0, 0, 0]
return [i64(small), i64(i8(-128)), i64(u32(4294967295)), i64(u8(255))]
}
""",
b"[255, -128, 4294967295, 255]\n", None,
),
"cast_unsigned_max": ("main proc() u64 { return u64(18446744073709551615) }", b"18446744073709551615\n", None),
"cast_float_rounding": ("main proc() f64 { return f64(9007199254740993) - 9007199254740992.0 }", b"0\n", None),
"cast_fractional": ("main proc() [4]i64 { return [i64(i8(-128.9)), i64(u8(-0.9)), i64(u8(255.9)), i64(i8(127.9))] }", b"[-128, 0, 255, 127]\n", None),
"cast_float_u64_max_below": ("main proc() u64 { return u64(18446744073709549568.0) }", b"18446744073709549568\n", None),
"cast_float_i64_min": ("main proc() i64 { return i64(-9223372036854775808.0) }", b"-9223372036854775808\n", None),
"cast_unused_trap": ("bad proc() u8 { return u8(256) }\nmain proc() int { return 42 }", b"42\n", None),
"cast_short_circuit": ("main proc() bool { return true or u8(256) == 0 }", b"true\n", None),
"cast_bool_invalid": ("main proc() u8 { return u8(true) }", b"", b""),
"cast_zero_arguments": ("main proc() u8 { return u8() }", b"", b"argument count"),
"cast_extra_arguments": ("main proc() u8 { return u8(1, 2) }", b"", b"argument count"),
"cast_type_as_value": ("main proc() int { u8\nreturn 42 }", b"", b"type name cannot"),
"integer_no_implicit_narrowing": ("main proc() u8 { a u16 :: 1\nreturn a }", b"", b"return does not match"),
"integer_no_implicit_signedness": ("main proc() i8 { a u8 :: 1\nreturn a }", b"", b"return does not match"),
"integer_no_implicit_widening": ("main proc() u16 { a u8 :: 1\nreturn a }", b"", b"return does not match"),
"integer_assignment_cast": (
"main proc() u8 { a u8 := 1\nb u16 :: 254\na = u8(b + 1)\nreturn a }",
b"255\n", None,
),
"integer_function_value": (
"identity proc(n i16) i16 { return n }\nmain proc() i16 { f :: identity\nreturn f(i16(-32768)) }",
b"-32768\n", None,
),
"integer_typed_float_cast": (
"main proc() f64 { a u64 :: 18446744073709551615\nreturn f64(a) - 18446744073709551616.0 }",
b"0\n", None,
),
"integer_bad_index": ("main proc() i64 { a :: [42]\ni u8 :: 0\nreturn a[i] }", b"", b"array index must have type usize"),
"integer_cast_index": ("main proc() i64 { a :: [42]\ni u8 :: 0\nreturn a[usize(i)] }", b"42\n", None),
"integer_cast_unknown": ("main proc() u8 { return u8(missing) }", b"", b"unknown name"),
"integer_cast_bad_unused": ("bad proc() u8 { return u8(true) }\nmain proc() int { return 42 }", b"42\n", b""),
})
for name, expression in {
"narrow": "u8(256)",
"signed_negative": "u8(-1)",
"signed_high": "i8(128)",
"unsigned_to_signed": "i64(u64(18446744073709551615))",
"float_high": "u8(256.0)",
"float_low": "i8(-129.0)",
"float_unsigned_negative": "u8(-1.0)",
"float_signed_limit": "i64(9223372036854775808.0)",
"float_unsigned_limit": "u64(18446744073709551616.0)",
"nan": "i32(0.0 / 0.0)",
"infinity": "u32(1.0 / 0.0)",
}.items():
CASES[f"cast_trap_{name}"] = (
f"main proc() i64 {{ return i64({expression}) }}", b"", b"integer arithmetic overflow",
)
def run(*args, env=None):
return subprocess.run(args, cwd=ROOT, capture_output=True, timeout=30, env=env)
def outcome(result):
return result.returncode, result.stdout, result.stderr
def check(source, executable, expected=None):
interpreted = run(str(HONEY), "run", str(source))
assert interpreted.returncode in (0, 1), outcome(interpreted)
if expected is not None:
stdout, error = expected
assert interpreted.stdout == stdout, (source.name, outcome(interpreted), stdout)
assert interpreted.returncode == (1 if error is not None else 0), outcome(interpreted)
if error is not None:
assert interpreted.stderr and error in interpreted.stderr, outcome(interpreted)
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(source), "-o", str(executable), optimization)
assert built.returncode in (0, 1), (source.name, optimization, outcome(built))
assert built.stdout == b"", outcome(built)
assert executable.is_file(), (source.name, outcome(built))
compiled = run(str(executable))
assert outcome(compiled) == outcome(interpreted), (
source.name, optimization, outcome(interpreted), outcome(compiled)
)
executable.unlink()
def check_packages(temporary, executable):
project = temporary / "packages"
def put(path, text):
target = project / path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(text)
return target
put("build.hon", "# project-root marker\n")
app = project / "app"
main = put("app/main.hon", 'import "../left"\nright :: import "@right"\nimport "../shared"\nmain proc() int { return helper(21) }\n')
helper = put("app/zhelper.bro", "helper proc(n int) int { return n * 2 }\n")
put("app/ignored.test.hon", "this is deliberately not valid source\n")
(app / "directory.hon").mkdir()
fifo = project / "pipe"
os.mkfifo(fifo)
(app / "pipe.hon").symlink_to(fifo)
put("left/left.hon", 'import "../shared"\nhelper proc() int { return 1 }\nmain proc() int { return 99 }\n')
put("right/right.hon", 'import "../shared-link"\nhelper proc() int { return 2 }\n')
shared = put("shared/shared.hon", "helper proc() int { return 3 }\n")
(project / "shared-link").symlink_to(project / "shared", target_is_directory=True)
check(app, executable, (b"42\n", None))
# File inputs retain their old single-file semantics, even inside a package.
check(main, executable, (b"", b"unknown name"))
emitted = run(str(HONEY), "emit-llvm", str(app))
assert emitted.returncode == 0 and emitted.stderr == b"", outcome(emitted)
shared.write_text("bad proc() int { return missing }\n")
check(app, executable, (b"42\n", b"unknown name"))
diagnosed = run(str(HONEY), "run", str(app))
assert diagnosed.stderr.count(b"unknown name") == 1, outcome(diagnosed)
assert str(shared.resolve()).encode() + b":1:" in diagnosed.stderr, outcome(diagnosed)
# Dependency main functions cannot supply an entry for the root package.
main.write_text('import "../left"\nentry proc() int { return 42 }\n')
shared.write_text("helper proc() int { return 3 }\n")
check(app, executable, (b"", b"program requires a main function"))
# Source scopes merge within a package, never across dependency packages.
main.write_text('import "../left"\nmain proc() int { return helper() }\n')
helper.write_text("local_only proc() int { return 7 }\n")
check(app, executable, (b"", b"unknown name"))
main.write_text('import "../left"\nmain proc() int { return 42 }\n')
shared.write_text('import "../left"\n')
check(app, executable, (b"42\n", b"package import cycle"))
shared.write_text('import "../shared-link"\n')
check(app, executable, (b"42\n", b"package import cycle"))
shared.write_text("helper proc() int { return 3 }\n")
for imported, message in (
("/tmp", b"invalid import path"),
("@/tmp", b"invalid import path"),
("../absent", b"cannot load package directory"),
("../shared/shared.hon", b"cannot load package directory"),
("../empty", b"cannot load package directory"),
):
(project / "empty").mkdir(exist_ok=True)
main.write_text(f'import "{imported}"\nmain proc() int {{ return 42 }}\n')
check(app, executable, (b"42\n", message))
main.write_text('test import "../absent"\nmain proc() int { return 42 }\n')
check(app, executable, (b"42\n", None))
# Directory order is lexical, not filesystem insertion order; first declaration wins.
put("duplicate/z.hon", "value :: 99\n")
put("duplicate/a.hon", "value :: 41\n")
put("duplicate/main.hon", "main proc() int { return value }\n")
check(project / "duplicate", executable, (b"41\n", b"duplicate name"))
# Runtime locations must survive source/frontend cleanup in generated executables.
main.write_text("main proc() int { return fail() }\n")
helper.write_text("\nfail proc() int { return 9223372036854775807 + 1 }\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
trapped = run(str(HONEY), "run", str(app))
assert str(helper.resolve()).encode() + b":2:" in trapped.stderr, outcome(trapped)
empty = run(str(HONEY), "run", str(project / "empty"))
assert empty.returncode == 2 and b"no production source files" in empty.stderr, outcome(empty)
special = run(str(HONEY), "run", str(fifo))
assert special.returncode == 2 and b"cannot open source file" in special.stderr, outcome(special)
return 15
def check_namespace_packages(temporary, executable):
project = temporary / "namespaces"
def put(path, text):
target = project / path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(text)
return target
put("build.hon", "# project root\n")
main = put("app/main.hon", """
import "../left"
right :: import "@right"
import "../shared-link"
main proc() int {
functions :: [left.helper, right.helper]
selected := left.helper
selected = right.helper
return sibling(18) + functions[0]() + selected() + shared.helper()
}
""")
sibling = put("app/sibling.hon", """
right :: import "../left"
sibling proc(n int) int { return n * 2 + right.helper() - 1 }
""")
put("left/main.hon", """
import "../shared"
helper proc() int { return shared.helper() - 2 }
identity proc(n int) int { return n }
main proc() int { return 99 }
""")
put("right/main.hon", """
import "../shared-link"
helper proc() int { return shared.helper() - 1 }
""")
dependency = put("shared/main.hon", """
helper proc() int { return value }
fail proc() int { return 9223372036854775807 + 1 }
""")
put("shared/zfunctions.bro", """
value :: 3
identity proc(n f64) f64 { return n }
""")
put("shared/ignored.test.bro", "this is deliberately not valid source\n")
(project / "shared-link").symlink_to(project / "shared", target_is_directory=True)
app = main.parent
check(app, executable, (b"42\n", None))
emitted = run(str(HONEY), "emit-llvm", str(app))
assert emitted.returncode == 0 and emitted.stderr == b"", outcome(emitted)
sibling.write_text("sibling proc(n int) int { return n * 2 }\n")
cases = [
('import "../left"\nmain proc() int { return left.helper() }', b"1\n", None),
('lib :: import "../shared"\nmain proc() f64 { f :: lib.identity\nreturn f(1.5) }', b"1.5\n", None),
('lib :: import "../shared"\nmain proc() int { return lib.value }', b"3\n", None),
("""
import "../left"
import "../shared"
main proc() bool {
return left.identity(41) == 41 and shared.identity(1.5) == 1.5
}
""", b"true\n", None),
('lib :: import "../shared"\nmain proc() int { return lib.absent() }', b"", b"unknown name"),
('lib :: import "../shared"\nmain proc() int { return helper() }', b"", b"unknown name"),
('import "../left"\nmain proc() int { return left.shared.helper() }', b"", b"unknown name"),
('import "../shared"\nmain proc() int { return shared.helper(1) }', b"", b"argument count"),
('import "../shared"\nmain proc() f64 { return shared.identity(true) }', b"", b"incompatible value type"),
('import "../shared"\nmain proc() int { shared\nreturn 42 }', b"", b"namespace cannot be used as a value"),
('import "../shared"\nmain proc() int { return shared.value.member }', b"", b""),
('lib :: import "../absent"\nmain proc() int { return lib.helper() }', b"", b"cannot load package directory"),
('lib :: import "../left"\nlib :: import "../right"\nmain proc() int { return lib.helper() }', b"1\n", b"duplicate name"),
('lib :: import "../shared"\nlib :: 42\nmain proc() int { return lib.helper() }', b"", b"duplicate name"),
('lib :: import "../shared"\nmain proc() int { lib :: 42\nreturn lib }', b"", b"duplicate name"),
('int :: import "../shared"\nmain proc() int { return 42 }', b"", b"duplicate name"),
('import "../shared"\nmain proc() int { shared.value = 42\nreturn 0 }', b"", b"mutable local binding"),
('import "../shared"\nmain proc() int { shared = 42\nreturn 0 }', b"", b"mutable local binding"),
('import "../shared"\nunused proc() int { return shared.absent() }\nmain proc() int { return 42 }', b"42\n", b"unknown name"),
('import "../shared"\nmain proc() int { return shared.fail() }', b"", b"integer arithmetic overflow"),
('import "../shared"\nmain proc() int { return shared. }', b"", b"unexpected token"),
]
for text, stdout, error in cases:
main.write_text(text + "\n")
check(app, executable, (stdout, error))
# Imports in a sibling file are invisible even though its declarations are shared.
main.write_text("main proc() int { return local.helper() }\n")
sibling.write_text('local :: import "../shared"\nsibling proc(n int) int { return n }\n')
check(app, executable, (b"", b"unknown name"))
# A missing package selection reuses the loader diagnostic instead of cascading.
main.write_text('lib :: import "../absent"\nmain proc() int { return lib.helper() }\n')
diagnosed = run(str(HONEY), "run", str(app))
assert diagnosed.stderr.count(b"cannot load package directory") == 1, outcome(diagnosed)
assert b"unknown name" not in diagnosed.stderr, outcome(diagnosed)
# Dependency diagnostics and reached traps preserve their original source file.
main.write_text('import "../shared"\nmain proc() int { return shared.helper() }\n')
dependency.write_text("helper proc() int { return missing }\n")
check(app, executable, (b"", b"unknown name"))
diagnosed = run(str(HONEY), "run", str(app))
assert str(dependency.resolve()).encode() + b":1:" in diagnosed.stderr, outcome(diagnosed)
dependency.write_text("\nhelper proc() int { return 9223372036854775807 + 1 }\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
trapped = run(str(HONEY), "run", str(app))
assert str(dependency.resolve()).encode() + b":2:" in trapped.stderr, outcome(trapped)
# File commands still load dependency siblings, but never their own siblings.
single = put("single/main.bro", """
import "../shared"
main proc() f64 { return shared.identity(42) }
""")
put("single/poison.hon", """
main proc() int { return missing }
""")
check(single, executable, (b"42\n", None))
emitted = run(str(HONEY), "emit-llvm", str(single))
assert emitted.returncode == 0 and emitted.stderr == b"", outcome(emitted)
check(single.parent, executable, (b"42\n", b"duplicate name"))
put("hidden/a.hon", "@hide:file\nhelper proc() int { return 20 }\nfirst proc() int { return helper() }\n")
put("hidden/b.hon", "@hide:file\nhelper proc() int { return 22 }\nsecond proc() int { return helper() }\n")
visibility_cases = (
('import "../hidden"\nmain proc() int { return hidden.first() + hidden.second() }\n', b"42\n", None),
('import "../hidden"\nmain proc() int { return hidden.helper() }\n', b"", b"unknown name"),
('@hide:file\nprivate proc() int { return 42 }\nmain proc() int { return private() }\n', b"42\n", None),
('@hide:package\nprivate proc() int { return 42 }\nmain proc() int { return private() }\n', b"", b"unexpected token"),
)
sibling.write_text("sibling proc(n int) int { return n }\n")
for text, stdout, error in visibility_cases:
main.write_text(text)
check(app, executable, (stdout, error))
sibling.write_text("@hide:file\nprivate proc() int { return 42 }\n")
main.write_text("main proc() int { return private() }\n")
check(app, executable, (b"", b"unknown name"))
return len(cases) + len(visibility_cases) + 7
def check_record_packages(temporary, executable):
project = temporary / "records"
app, library = project / "app", project / "library"
app.mkdir(parents=True)
library.mkdir()
types = library / "types.hon"
types.write_text("Point :: struct { x i16, y i16 = 2 }\n")
(library / "functions.hon").write_text("identity proc(p Point) Point { return p }\n")
(app / "main.hon").write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
p lib.Point := lib.Point { x = 40 }
q :: lib.identity(p)
p.x = 1
return q.x + q.y
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
(library / "functions.hon").write_text(
"set proc(p @mut Point) void { p.x = 40 }\n"
"identity proc(p @mut Point) @mut Point { return p }\n"
)
(app / "main.hon").write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
p lib.Point := { x = 1 }
pointer :: lib.identity(&p)
lib.set(pointer)
return pointer.x + p.y
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
types.write_text("Point :: struct { x i16, y i16 = 32767 + 1 }\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
trapped = run(str(HONEY), "run", str(app))
assert trapped.stderr.startswith(f"{types.resolve()}:1:".encode()), outcome(trapped)
types.write_text(
"Point :: struct { x i16, y i16 = 2 }\n"
"Callback :: alias @proc(p @mut Point, amount i16) i16\n"
"VTable :: struct { run Callback }\n"
)
(library / "functions.hon").write_text(
"increment proc(p @mut Point, amount i16) i16 { p.x = p.x + amount\nreturn p.x + p.y }\n"
"invoke proc(table VTable, values *mut Point) i16 { return table.run(&(values + 1)^, 40) }\n"
)
(app / "main.hon").write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
values [2]mut lib.Point := [lib.Point { x = 7 }, lib.Point { x = 0 }]
callback lib.Callback :: lib.increment
table :: lib.VTable { run = callback }
result :: lib.invoke(table, (&values).ptr)
if (values[0].x != 7 or values[1].x != 40) return -1
return result
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
types.write_text(textwrap.dedent("""
Generated proc(bias i16) type {
return struct_type!(.auto, ["value", "bias"], [i16, i16], [null, bias])
}
""").strip() + "\n")
(library / "functions.hon").write_text(
"identity proc(value Generated(2)) Generated(2) { return value }\n"
)
(app / "main.hon").write_text(textwrap.dedent("""
lib :: import "../library"
Selected :: alias lib.Generated(2)
main proc() i16 {
value Selected :: { value = 40 }
same lib.Generated(2) :: lib.identity(value)
return same.value + same.bias
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
types.write_text(textwrap.dedent("""
Generated proc(bias i16) type {
return struct_type!(.auto, ["bad-name"], [i16], [null])
}
""").strip() + "\n")
check(app, executable, (b"", b"generated field name"))
diagnosed = run(str(HONEY), "run", str(app))
assert diagnosed.stderr.startswith(f"{types.resolve()}:2:".encode()), outcome(diagnosed)
return 6
def check_data_model_packages(temporary, executable):
project = temporary / "data-models"
app, library = project / "app", project / "library"
app.mkdir(parents=True)
library.mkdir()
(library / "types.hon").write_text(textwrap.dedent("""
Kind :: enum { number, empty }
Id :: distinct i16
Choice :: union(Kind) { empty void, number Id }
Count :: alias Id
seed Id :: Id(41)
""").strip() + "\n")
(library / "functions.hon").write_text(textwrap.dedent("""
identity proc(c Choice) Choice { return c }
score proc(c Choice) Id {
return match c { .number |n|: n + 1, .empty: Id(0) }
}
invoke :: alias score
""").strip() + "\n")
source = app / "main.hon"
source.write_text(textwrap.dedent("""
lib :: import "../library"
Alias :: alias lib.Choice
call :: alias lib.invoke
shared :: alias lib.seed
main proc() i16 {
value Alias :: { number = shared }
return i16(call(lib.identity(value)))
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
# Distinct and enum identity remain package/declaration specific.
for declaration, body in (
("Id :: distinct i16", "return lib.seed"),
("Kind :: enum { number, empty }", "return lib.Kind.number"),
):
result = declaration.split()[0]
source.write_text(
'lib :: import "../library"\n'
+ declaration + f"\nmain proc() {result} {{ {body} }}\n"
)
check(app, executable, (b"", b"return does not match"))
return 3
def check_specialization_packages(temporary, executable):
project = temporary / "specialization"
app, library = project / "app", project / "library"
app.mkdir(parents=True)
library.mkdir()
(library / "types.hon").write_text(textwrap.dedent("""
Box proc(T type) type {
return struct { value match true { true: T, false: i8(128) } }
}
Selected proc(wide bool) type {
return match wide { true: i16, false: u8 }
}
Fixed proc($T type, N usize) type {
Element := i8
length usize := 0
while (length < N) {
Element = T
length = length + 1
}
return struct { values [match length { 0: usize(0), else: length }]mut Element }
}
Choice :: union(enum) { count usize, empty void }
Captured proc(T type, choice Choice) type {
return match choice {
.count |length|: struct { values [length]T },
.empty: bool,
}
}
TypeRecord proc(T type) type {
config struct { child type, count usize } := { child = i8, count = 1 }
original :: config
config.child = T
config.count = 2
if (original.child != i8 or original.count != 1) return bool
return struct { values [config.count]config.child }
}
""").strip() + "\n")
(library / "functions.hon").write_text(textwrap.dedent("""
identity proc($T type, value T) T { return value }
first proc($T type, $N usize, value @Fixed(T, N)) T {
return value.values[0]
}
count proc() usize {
result := 0
while (result < 2) result = result + 1
return result
}
selected proc($choice Choice, value i16) i16 {
match choice {
.count |length|: {
return match length { 2: value + i16(length), else: value.missing }
}
.empty: return value.missing,
}
}
""").strip() + "\n")
source = app / "main.hon"
source.write_text(textwrap.dedent("""
lib :: import "../library"
Element :: alias lib.Selected(true)
ImportedBox :: alias lib.Box(Element)
main proc() i16 {
imported ImportedBox :: { value = 40 }
copy lib.Box(i16) :: imported
captured lib.Captured(ImportedBox, .count{2}) :: { values = [imported, copy] }
fixed lib.Fixed(i16, lib.count()) :: { values = [2, 0] }
return captured.values[0].value + lib.identity(lib.first(&fixed))
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
value lib.Captured(i16, .count{2}) :: { values = [20, 20] }
return lib.selected(.count{2}, value.values[0] + value.values[1])
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
value lib.TypeRecord(i16) :: { values = [19, 23] }
same lib.TypeRecord(i16) :: value
return same.values[0] + same.values[1]
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
source.write_text(textwrap.dedent("""
lib :: import "../library"
Box proc($T type) type { return struct { value T } }
main proc() i16 {
imported lib.Box(i16) :: { value = 42 }
local Box(i16) :: imported
return local.value
}
""").strip() + "\n")
check(app, executable, (b"", b"incompatible value type"))
sizing = library / "sizing.hon"
sizing.write_text(textwrap.dedent("""
size proc() usize {
high usize :: 18446744073709551615
return high + 1
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
if (false) {
fixed lib.Fixed(i16, lib.size()) :: { values = [40, 2] }
return fixed.values[0]
}
return 42
}
""").strip() + "\n")
check(app, executable, (b"42\n", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:12: ".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Bad proc() type {
return struct { value match true { true: i16, true: i8, else: bool } }
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() lib.Bad() { return 42 }
""").strip() + "\n")
check(app, executable, (b"", b"duplicate or overlapping match pattern"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:2:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
SizingChoice :: union(enum) { small i8 }
Bad proc() type {
input SizingChoice :: .small{127}
match input {
.small |value|: {
next :: value + 1
return [usize(next)]i16
}
}
}
""").strip() + "\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:6:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Optional proc(T type, size ?usize) type {
if size |length| { return struct { values [length]T } }
else { return bool }
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
value lib.Optional(i16, 2) :: { values = [40, 2] }
return value.values[0] + value.values[1]
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
narrow proc() ?i8 { return 127 }
Optional proc(T type, size ?usize) type {
if narrow() |value| {
next :: value + 1
return [usize(next)]T
}
return T
}
""").strip() + "\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:4:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Updated proc() type {
config struct { counts [2]mut usize, bias i16 } := { counts = [0, 0], bias = 40 }
config.counts[1] = 2
config.bias = config.bias + i16(config.counts[1])
return struct { values [config.counts[1]]i16, bias i16 = config.bias }
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
value lib.Updated() :: { values = [0, 0] }
return value.bias
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
Updated proc() type {
counts [1]mut usize := [1]
counts[1] = 2
return [counts[0]]i16
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.Updated() { return [0] }\n')
check(app, executable, (b"", b"index out of bounds"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Collected proc() type {
values [2]usize :: [1, 1]
length usize := 0
for values |value, index| { length = length + value + index }
return [length]i16
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
values lib.Collected() :: [19, 21, 2]
same lib.Collected() :: values
total i16 := 0
for same |value| { total = total + value }
return total
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
Collected proc() type {
values [1]i8 :: [127]
for values |value| { next :: value + 1 }
return i16
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.Collected() { return 0 }\n')
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
TypeArray proc() type {
types [2]mut type := [i8, bool]
for types |T, index| {
if (index == 0) types[1] = i16
if (index == 1) return struct { values [2]T, bias T = 2 }
}
return bool
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
value lib.TypeArray() :: { values = [19, 21] }
same lib.TypeArray() :: value
return same.values[0] + same.values[1] + same.bias
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
TypeArray proc() type {
types [1]mut type := [i16]
types[1] = bool
return types[0]
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.TypeArray() { return 42 }\n')
check(app, executable, (b"", b"index out of bounds"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
row proc($N usize, types [N]type) [N]type { return types }
rows proc() [1][2]type { return [row(2, [i16, bool])] }
FromTypes proc(types [2]type) type {
return struct { value types[0], enabled types[1] = true }
}
add proc($types [2]type, value types[0]) types[0] { return value + 2 }
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
Imported :: alias lib.FromTypes(lib.rows()[0])
read proc(value lib.rows()[0][0]) i16 {
return lib.add(lib.row(2, [i16, bool]), value)
}
main proc() i16 {
value Imported :: { value = 40 }
same lib.FromTypes([i16, bool]) :: value
if (same.enabled) return read(same.value)
return 0
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
row proc() [1]type { return [i16] }
bad_rows proc() [1][1]type { return [[row()[1]]] }
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.bad_rows()[0][0] { return 42 }\n')
check(app, executable, (b"", b"index out of bounds"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:2:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
BadRecord proc() type {
config :: { child = i16, count = i8(127) }
next :: config.count + 1
return [usize(next)]config.child
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.BadRecord() { return 42 }\n')
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Config :: struct { child type, counts [2]mut usize, bias i16 = 2 }
record_config proc() Config { return { child = i16, counts = [1, 2] } }
FromRecord proc(input Config) type {
return struct { values [input.counts[1]]input.child, bias i16 = input.bias }
}
add proc($input Config, value input.child) input.child { return value + input.bias }
NominalConfig :: struct { child type }
nominal_config proc() NominalConfig {
return { child = struct { value i16 } }
}
FromNominal proc(input NominalConfig) type { return struct { value input.child } }
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
Imported :: alias lib.FromRecord(lib.record_config())
main proc() i16 {
value Imported :: { values = [19, 21] }
same lib.FromRecord({ child = i16, counts = [1, 2] }) :: value
nominal lib.FromNominal(lib.nominal_config()) :: { value = { value = 40 } }
same_nominal lib.FromNominal(lib.nominal_config()) :: nominal
if (same_nominal.value.value != 40) return 0
return lib.add(lib.record_config(), same.values[0] + same.values[1])
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
Config :: struct { child type, rows [1]mut [1]mut type }
record_config proc() Config { return { child = i16, rows = [[i16]] } }
bad_config proc() Config {
copied := record_config()
copied.child = copied.rows[0][1]
return copied
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.bad_config().child { return 42 }\n')
check(app, executable, (b"", b"index out of bounds"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:5:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
values proc() [2]i16 { return [19, 22] }
types proc() [2]type { return [i16, bool] }
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
add proc(value i16, index usize) i16 { return value + i16(index) }
main proc() i16 {
total i16 := 0
inline for lib.values() |value, index| { total = total + add(value, index) }
inline for lib.types() |T| {
if (T == i16) {
value T :: total
total = value
} else {
value T :: true
if (!value) return 0
}
}
return total
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
values proc() [1]i16 {
value i8 :: 127
overflow :: value + 1
return [i16(overflow)]
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() i16 {
inline for lib.values() |value| { return value }
return 0
}
""").strip() + "\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:3:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
sizing.write_text(textwrap.dedent("""
Callback :: alias @proc(value i16) i16
bias i16 :: 1
@hide:file
increment proc(value i16) i16 { return value + bias }
choose proc() Callback { return increment }
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
increment proc(value i16) i16 { return value + 100 }
main proc() i16 {
callback :: $(lib.choose())
return callback(41)
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
bytes [3]u8 :: [9, 40, 2]
view proc() []u8 { return bytes[1..] }
filled proc() []u8 {
local [2]mut u8 := undefined
local[0] = 40
local[1] = 2
return local[..]
}
Token proc($value []u8) type { return struct {} }
Generated proc() type {
return struct_type!(.auto, ["value"], [[]u8], [filled()])
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() [3]u8 {
value lib.Generated() :: {}
direct :: $(lib.view())
if (lib.Token(lib.view()) != lib.Token(lib.filled())) return [0, 0, 0]
return [direct[0], value.value[1], $(lib.filled())[0]]
}
""").strip() + "\n")
check(app, executable, (b"[40, 2, 40]\n", None))
sizing.write_text(textwrap.dedent("""
Storage :: union { small u16, words [2]mut u16 }
make proc() Storage {
value := Storage { words = [0, 2] }
value.small = 40
return value
}
Token proc($value Storage) type { return struct {} }
Generated proc() type {
return struct_type!(.auto, ["value"], [Storage], [make()])
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() u16 {
direct :: $(lib.make())
value lib.Generated() :: {}
if (lib.Token(lib.make()) != lib.Token(lib.Storage { words = [40, 2] })) return 0
return direct.small + value.value.words[1]
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
sizing.write_text(textwrap.dedent("""
Storage :: union { small u8, words [2]u64 }
make proc() Storage {
value u8 :: 255
overflow :: value + 1
return Storage { words = [u64(overflow), 2] }
}
""").strip() + "\n")
source.write_text(textwrap.dedent("""
lib :: import "../library"
main proc() u8 { return $(lib.make()).small }
""").strip() + "\n")
check(app, executable, (b"", b"integer arithmetic overflow"))
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.stderr.startswith(f"{sizing.resolve()}:4:".encode()), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
return 26
def check_dependency_provenance(temporary, executable):
project = temporary / "provenance"
app = project / "app"
dependency = project / "dependency"
app.mkdir(parents=True)
dependency.mkdir()
main = app / "main.hon"
source = dependency / "diagnostic.hon"
# A transitive call must report the leaf's location, not either importing file.
bridge = project / "bridge"
bridge.mkdir()
(bridge / "main.hon").write_text(textwrap.dedent("""
import "../dependency"
fail proc() int { return dependency.fail() }
""").strip() + "\n")
cases = [
("""
fail proc() int {
return {
yield 9223372036854775807 + 1
}
}
""", 5, 15, False),
("""
fail proc() int {
return {
yield missing
}
}
""", 5, 15, True),
("""
fail proc() int {
return `
}
""", 4, 12, True),
("""
fail proc() int {
return (1
}
""", 4, 14, True),
("""
fail proc() int {
text :: "é" return missing
}
""", 4, 25, True),
("""
fail proc() int {
if (1) return 0
return 42
}
""", 4, 9, True),
("""
fail proc() int {
return 9223372036854775808
}
""", 4, 12, True),
("""
fail proc() int {
return 9223372036854775807 + 1
}
""", 4, 12, False),
("""
fail proc() int {
inline for [int(9223372036854775807)] |value| {
return value + 1
}
return 42
}
""", 5, 16, False),
("""
Choice :: union(enum) { number int, empty void }
fail proc() int {
input Choice :: .number{9223372036854775807}
return match input {
inline |payload, tag|: match tag {
.number: payload + 1,
.empty: 0,
},
}
}
""", 8, 22, False),
("""
fail proc() int {
a :: [42]
return a[1]
}
""", 5, 12, False),
("""
fail proc() int {
a :: [42]
pointer :: &a
return pointer[1]
}
""", 6, 12, False),
("""
fail proc() int {
before :: after
after :: 42
return before
}
""", 4, 15, False),
("""
a int :: b
b int :: a
fail proc() int { return a }
""", 4, 10, False),
]
for text, line, column, static in cases:
source.write_text("\n# utf8: é\n" + textwrap.dedent(text).strip() + "\n")
location = f"{source.resolve()}:{line}:{column}: ".encode()
for reached in (False, True):
main.write_text(textwrap.dedent(f"""
import "../bridge"
main proc() int {{
if ({str(reached).lower()}) return bridge.fail()
return 42
}}
""").strip() + "\n")
interpreted = run(str(HONEY), "run", str(app))
assert interpreted.returncode == int(static or reached), outcome(interpreted)
assert interpreted.stdout == (b"" if reached else b"42\n"), outcome(interpreted)
if static or reached:
label = b"runtime trap: " if reached else b"error: "
assert interpreted.stderr.startswith(location + label), outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
else:
assert interpreted.stderr == b"", outcome(interpreted)
emitted = run(str(HONEY), "emit-llvm", str(app))
assert emitted.returncode == int(static), outcome(emitted)
expected_diagnostics = interpreted.stderr.replace(b"runtime trap: ", b"error: ") if static else b""
assert emitted.stderr == expected_diagnostics, outcome(emitted)
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(app), "-o", str(executable), optimization)
assert outcome(built) == (int(static), b"", expected_diagnostics), outcome(built)
# Generated diagnostics must not reopen sources at runtime.
hidden = project.with_name("hidden-provenance")
project.rename(hidden)
try:
compiled = run(str(executable))
assert outcome(compiled) == outcome(interpreted), (
optimization, outcome(interpreted), outcome(compiled)
)
finally:
hidden.rename(project)
executable.unlink()
return len(cases) * 2
def check_arraylist_packages(temporary, executable):
project = temporary / "arraylist"
project.mkdir()
(project / "build.hon").write_text("# project root\n")
for package in ("std", "ffi"):
(project / package).symlink_to(ROOT / package, target_is_directory=True)
source = project / "main.hon"
# A fixed-capacity test allocator lets the interpreter exercise the real
# library's growth/failure paths without executing foreign calls.
source.write_text(textwrap.dedent("""
import "@std/arraylist"
import "@std/mem"
State :: struct { storage *mut i16, fail bool = false, allocations usize = 0, releases usize = 0 }
allocate proc(context ?@mut anyopaque, size usize, alignment usize) ?*mut u8 {
state @mut State :: ptrcast!(context?)
state.allocations = state.allocations + 1
if (state.fail or size > sizeof!([64]i16) or alignment > alignof!(i16)) return null
return ptrcast!(state.storage)
}
resize proc(
context ?@mut anyopaque, _ ?*mut u8, _ usize, size usize, alignment usize,
) ?*mut u8 { return allocate(context, size, alignment) }
release proc(context ?@mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {
state @mut State :: ptrcast!(context?)
state.releases = state.releases + 1
}
table mem.AllocatorVTable :: { alloc = allocate, realloc = resize, free = release }
fail proc(allocator mem.Allocator) void ! mem.AllocError {
list := arraylist.init(i16, allocator)
defer arraylist.deinit(&list)
try arraylist.append(&list, 42)
return .out_of_memory
}
main proc() i16 ! mem.AllocError {
storage [64]mut i16 := undefined
state State := { storage = (&storage).ptr }
allocator mem.Allocator :: { context = &state, vtable = &table }
list := arraylist.init(i16, allocator)
if (list.items.len != 0 or list.capacity != 0 or state.allocations != 0) return -1
if (arraylist.pop(&list) != null) return -2
for (i16(0)..20) |value| { try arraylist.append(&list, value) }
if (list.items.len != 20 or list.capacity < 20) return -3
for list.items |value, index| { if (value != i16(index)) return -4 }
previous_capacity :: list.capacity
previous_calls :: state.allocations
try arraylist.reserve(&list, previous_capacity)
if (state.allocations != previous_calls) return -5
state.fail = true
arraylist.reserve(&list, previous_capacity + 1) catch |err| {
if (err != .out_of_memory) return -6
}
if (list.capacity != previous_capacity or list.items.len != 20 or list.items[19] != 19) return -7
if (state.allocations != previous_calls + 1) return -8
if (arraylist.pop(&list)? != 19 or list.items.len != 19) return -9
arraylist.clear(&list)
if (list.items.len != 0 or list.capacity != previous_capacity) return -10
state.fail = false
try arraylist.append(&list, 42)
if (list.items[0] != 42 or state.allocations != previous_calls + 1) return -11
arraylist.deinit(&list)
if (list.items.len != 0 or list.capacity != 0 or state.releases != 1) return -12
arraylist.deinit(&list)
if (state.releases != 1) return -13
fail(allocator) catch {}
if (state.releases != 2) return -14
state.fail = true
arraylist.append(&list, 1) catch {}
if (list.items.len != 0 or list.capacity != 0) return -15
return 42
}
""").strip() + "\n")
check(source, executable, (b"42\n", None))
source.write_text(textwrap.dedent("""
import "@std/arraylist"
import "@std/mem"
Empty :: struct {}
main proc() i16 ! mem.AllocError {
list := arraylist.init(Empty, mem.c_allocator)
defer arraylist.deinit(&list)
try arraylist.reserve(&list, 20)
for (0..21) |_| { try arraylist.append(&list, Empty{}) }
if (list.items.len != 21 or list.capacity < 21) return -1
if (arraylist.pop(&list) == null or list.items.len != 20) return -2
arraylist.clear(&list)
if (list.items.len != 0 or arraylist.pop(&list) != null) return -3
return 42
}
""").strip() + "\n")
check(source, executable, (b"42\n", None))
native_cases = (
"""
import "@std/arraylist"
import "@std/mem"
Item :: struct { number i16, values [2]mut i16 }
main proc() i16 ! mem.AllocError {
list := arraylist.init(Item, mem.c_allocator)
defer arraylist.deinit(&list)
for (i16(0)..32) |value| {
try arraylist.append(&list, Item{ number = value, values = [value, 2] })
}
if (list.items.len != 32 or list.capacity < 32) return -1
saved :: list.items[20]
list.items[20].values[0] = 0
if (saved.values[0] != 20) return -2
for list.items |item, index| { if (item.number != i16(index)) return -3 }
if (arraylist.pop(&list)?.number != 31) return -4
arraylist.clear(&list)
try arraylist.append(&list, saved)
return list.items[0].number + list.items[0].values[0] + list.items[0].values[1]
}
""",
"""
import "@std/mem"
main proc() i16 {
allocator :: mem.c_allocator
if (mem.raw_alloc(allocator, 16, 3) != null) return -1
initial :: mem.raw_alloc(allocator, 16, 64)
if initial |bytes| {
values *mut i16 :: ptrcast!(bytes)
values[0] = 40
values[1] = 2
resized :: mem.raw_realloc(allocator, bytes, 16, 128, 64)
if resized |grown| {
defer mem.raw_free(allocator, grown, 128, 64)
result *i16 :: ptrcast!(grown)
return result[0] + result[1]
}
mem.raw_free(allocator, bytes, 16, 64)
}
return -2
}
""",
)
for text in native_cases:
source.write_text(textwrap.dedent(text).strip() + "\n")
interpreted = run(str(HONEY), "run", str(source))
assert interpreted.returncode == 1 and interpreted.stdout == b"", outcome(interpreted)
assert b"foreign function calls are unsupported by the interpreter" in interpreted.stderr, outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(source), "-o", str(executable), optimization)
assert outcome(built) == (0, b"", b""), outcome(built)
assert outcome(run(str(executable))) == (0, b"42\n", b""), optimization
executable.unlink()
return 2, len(native_cases)
def check_allocator_libc(temporary, executable):
source = temporary / "allocator_libc.hon"
source.write_text(textwrap.dedent("""
malloc c_func(size c_ulong) ?*mut anyopaque
realloc c_func(memory ?*mut anyopaque, size c_ulong) ?*mut anyopaque
free c_func(memory ?*mut anyopaque) void
posix_memalign c_func(output *mut ?*mut anyopaque, alignment c_ulong, size c_ulong) c_int
VTable :: struct {
alloc @proc(context ?@mut anyopaque, size usize, alignment usize) ?*mut u8
release @proc(context ?@mut anyopaque, memory ?*mut u8) void
}
Allocator :: struct { context ?@mut anyopaque, vtable @VTable }
allocate proc(_ ?@mut anyopaque, size usize, alignment usize) ?*mut u8 {
if (alignment <= 16) return ptrcast!(malloc(c_ulong(size)))
output [1]mut ?*mut anyopaque := [null]
status :: posix_memalign((&output).ptr, c_ulong(alignment), c_ulong(size))
if (status != 0) return null
return ptrcast!(output[0])
}
release proc(_ ?@mut anyopaque, memory ?*mut u8) void { free(memory) }
table VTable :: { alloc = allocate, release = release }
main proc() i16 {
allocator Allocator :: { context = null, vtable = &table }
memory :: allocator.vtable.alloc(allocator.context, 4, 8)
if memory |bytes| {
values *mut i16 :: ptrcast!(bytes)
values[0] = 40
values[1] = 2
resized ?*mut i16 :: ptrcast!(realloc(bytes, 8))
if resized |items| {
aligned :: allocator.vtable.alloc(null, 8, 64)
if aligned |other| {
target *mut i16 :: ptrcast!(other)
memcopy!(target[..2], items[..2])
answer :: target[0] + target[1]
allocator.vtable.release(null, other)
free(items)
return answer
}
free(items)
return -1
}
free(bytes)
return -2
}
return -3
}
""").strip() + "\n")
interpreted = run(str(HONEY), "run", str(source))
assert interpreted.returncode == 1 and interpreted.stdout == b"", outcome(interpreted)
assert b"foreign function calls are unsupported by the interpreter" in interpreted.stderr, outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(source), "-o", str(executable), optimization)
assert outcome(built) == (0, b"", b""), outcome(built)
assert outcome(run(str(executable))) == (0, b"42\n", b""), optimization
executable.unlink()
return 1
def check_fallible_packages_and_entry(temporary, executable):
project = temporary / "fallible_packages"
app = project / "app"
library = project / "library"
app.mkdir(parents=True)
library.mkdir()
dependency = library / "error.hon"
dependency.write_text(
"Error :: enum { unavailable }\n"
"read proc() i16 ! Error { return .unavailable }\n"
)
source = app / "main.hon"
source.write_text(textwrap.dedent("""
library :: import "../library"
LocalError :: enum { local }
read proc() i16 ! (LocalError | library.Error) {
return try library.read()
}
main proc() i16 {
return read() catch |err| match err {
.local: 0,
.unavailable: 42,
}
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
count = 1
for result, body, expected in (
("i16", "return 42", (0, b"42\n", b"")),
("void", "return", (0, b"", b"")),
("void", "", (0, b"", b"")),
("i16", "return .failed", (1, b"", b"")),
("void", "return .failed", (1, b"", b"")),
):
source.write_text(
f"Error :: enum {{ failed }}\n"
f"main proc() {result} ! Error {{ {body} }}\n"
)
assert outcome(run(str(HONEY), "run", str(source))) == expected
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(source), "-o", str(executable), optimization)
assert outcome(built) == (0, b"", b""), outcome(built)
assert outcome(run(str(executable))) == expected, optimization
executable.unlink()
count += 1
return count
def check_typeinfo_packages(temporary, executable):
project = temporary / "typeinfo"
project.mkdir()
(project / "build.hon").write_text("# project root\n")
(project / "std").mkdir()
for package in ("meta", "enummap"):
(project / "std" / package).symlink_to(ROOT / "std" / package, target_is_directory=True)
cases = {
"categories_specialize_generic_calls": (
"""
reflection :: import "@std/meta"
Error :: enum { failed }
Choice :: union(enum) { number i16, empty void }
Raw :: union { number i16, flag bool }
category proc($T type) i16 {
return match typeinfo!(T) {
.integer: 1,
.bool: 2,
.float: 3,
.void: 4,
.anyopaque: 5,
.pointer: 6,
.slice: 7,
.optional: 8,
.function: 9,
.union: 10,
.fallible: 11,
else: -1,
}
}
widen proc($T type, value T) i16 {
return match typeinfo!(T) {
.integer: i16(value),
.bool: match value { true: 23, false: 0 },
else: value.missing,
}
}
main proc() [14]i16 {
return [
category(i8), category(bool), category(f64), category(void),
category(anyopaque), category(@mut i16), category([]u8),
category(?i16), category(proc(value i16) i16),
category(Choice), category(i16 ! Error), category(Raw),
category(string), widen(i8(19)) + widen(true),
]
}
""", b"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 6, 42]\n", None,
),
"arrays_and_immediate_distinct_backing": (
"""
import "@std/meta"
Inner :: distinct u16
Outer :: distinct Inner
Other :: distinct u16
OuterAlias :: alias Outer
ArrayAlias :: alias [3]Inner
array_matches proc($T, $Child type, $length usize) bool {
return match typeinfo!(T) {
.array |info|: info.child == Child and info.len == length,
else: false,
}
}
backing_matches proc($T, $Backing type) bool {
return match typeinfo!(T) {
.distinct |backing|: backing == Backing,
else: false,
}
}
main proc() bool {
return $(
array_matches(ArrayAlias, Inner, 3)
and array_matches([0]bool, bool, 0)
and array_matches([2]mut i16, i16, 2)
and !array_matches(ArrayAlias, Other, 3)
and backing_matches(Inner, u16)
and backing_matches(OuterAlias, Inner)
and !backing_matches(Outer, u16)
and OuterAlias == Outer and Inner != Other
)
}
""", b"true\n", None,
),
"record_tuple_names_order_exact_types_and_layout": (
"""
import "@std/meta"
Child :: struct { value i16 }
Other :: struct { value i16 }
Record :: struct { child Child, maybe ?i8, pointer @u8 }
RecordAlias :: alias Record
Tuple :: alias struct { i8, Child, bool }
Packet :: struct_type!(.c, ["value"], [i16], [null])
same_name proc(left, right []u8) bool {
if (left.len != right.len) return false
for left |byte, index| {
if (byte != right[index]) return false
}
return true
}
valid proc() bool {
match typeinfo!(RecordAlias) {
.record |info|: {
if (info.is_tuple or info.layout != .auto) return false
if (!same_name(info.name?, "Record") or info.fields.len != 3) return false
if (!same_name(info.fields[0].name, "child") or info.fields[0].index != 0) return false
if (!same_name(info.fields[1].name, "maybe") or info.fields[1].index != 1) return false
if (!same_name(info.fields[2].name, "pointer") or info.fields[2].index != 2) return false
if (info.fields[0].type != Child or info.fields[0].type == Other) return false
if (info.fields[1].type != ?i8 or info.fields[2].type != @u8) return false
}
else: return false,
}
match typeinfo!(Tuple) {
.record |info|: {
if (!info.is_tuple or info.name != null or info.layout != .auto) return false
if (info.fields.len != 3) return false
inline for info.fields |field, index| {
if (field.index != index or field.name.len != 1) return false
if (field.name[0] != u8(48 + index)) return false
if (index == 0 and field.type != i8) return false
if (index == 1 and field.type != Child) return false
if (index == 2 and field.type != bool) return false
}
}
else: return false,
}
match typeinfo!(struct { value i16 }) {
.record |info|: if (info.name != null or info.is_tuple) return false,
else: return false,
}
return match typeinfo!(Packet) {
.record |info|: info.layout == .c and !info.is_tuple,
else: false,
}
}
main proc() bool { return $(valid()) }
""", b"true\n", None,
),
"enum_metadata_uses_declaration_order_not_discriminants": (
"""
import "@std/meta"
Sparse :: enum(i16) { last = -7, first = 3, middle = 90 }
SparseAlias :: alias Sparse
Other :: enum(i16) { last = -7, first = 3, middle = 90 }
valid proc() bool {
return match typeinfo!(SparseAlias) {
.enum |info|: (
info.fields.len == 3
and info.fields[0].index == 0
and info.fields[1].index == 1
and info.fields[2].index == 2
and info.fields[0].name.len == 4 and info.fields[0].name[0] == 108
and info.fields[1].name.len == 5 and info.fields[1].name[0] == 102
and info.fields[2].name.len == 6 and info.fields[2].name[0] == 109
and info.fields[0].type == Sparse
and info.fields[1].type == SparseAlias
and info.fields[2].type != Other
),
else: false,
}
}
main proc() [3]mut i16 {
if (!$(valid())) return [0, 0, 0]
values [3]mut i16 := [0, 0, 0]
match typeinfo!(SparseAlias) {
.enum |info|: inline for info.fields |field, index| {
values[index] = i16(field!(SparseAlias, field.name))
}
else: compile_error!("expected enum"),
}
return values
}
""", b"[-7, 3, 90]\n", None,
),
"record_fields_drive_field_access_and_generic_inference": (
"""
import "@std/meta"
Record :: struct { small i8, wide i16, enabled bool }
convert proc($T type, value T) i16 {
return match typeinfo!(T) {
.integer: i16(value),
.bool: match value { true: 2, false: 0 },
else: compile_error!("unsupported field"),
}
}
sum proc($T type, value T) i16 {
total i16 := 0
match typeinfo!(T) {
.record |info|: inline for info.fields |field| {
total = total + convert(field!(value, field.name))
}
else: compile_error!("expected record"),
}
return total
}
main proc() i16 {
value Record :: { small = 19, wide = 21, enabled = true }
return sum(value)
}
""", b"42\n", None,
),
"reflected_fields_generate_owned_schema_and_defaults": (
"""
import "@std/meta"
Source :: struct { left i16, right i16 }
Defaults proc($T type, $default i16) type {
match typeinfo!(T) {
.record |info|: {
names [info.fields.len]mut []u8 := undefined
types [info.fields.len]mut type := undefined
defaults [info.fields.len]mut ?i16 := undefined
inline for info.fields |field, index| {
names[index] = field.name
types[index] = field.type
defaults[index] = default
}
return struct_type!(info.layout, names, types, defaults)
}
else: compile_error!("expected record"),
}
}
main proc() i16 {
first Defaults(Source, 21) := {}
saved :: first
field!(first, "left") = 0
same Defaults(Source, 21) :: saved
return same.left + same.right
}
""", b"42\n", None,
),
"real_meta_enum_field_struct_defaults": (
"""
import "@std/meta"
Key :: enum(i16) { last = -7, first = 3, middle = 90 }
Values :: alias meta.EnumFieldStruct(Key, i16, 21)
main proc() i16 {
values Values :: { last = 19, first = 23 }
empty Values :: {}
if (values.middle != 21 or empty.last != 21 or empty.first != 21) return -1
return values.last + field!(values, "first")
}
""", b"42\n", None,
),
"real_enummap_generates_ordinal_storage": (
"""
import "@std/meta"
import "@std/enummap"
Key :: enum(i16) { last = -7, first = 3, missing = 90 }
KeyAlias :: alias Key
main proc() i16 {
values enummap.EnumMap(KeyAlias, i16) :: {
present = [true, true, false], values = [19, 23, 0],
}
if (values.present[2]) return -1
return values.values[0] + values.values[1]
}
""", b"42\n", None,
),
"real_enummap_init_get_sparse_alias_and_absence": (
"""
import "@std/meta"
import "@std/enummap"
Key :: enum(i16) { last = -7, first = 3, missing = 90 }
KeyAlias :: alias Key
main proc() i16 {
values :: enummap.init(KeyAlias, i16, { last = 19, first = 23 })
empty :: enummap.init(Key, i16, {})
if (enummap.get(&values, .missing) != null) return -1
if (enummap.get(&empty, .first) != null) return -2
return enummap.get(&values, .last)? + enummap.get(Key, i16, &values, .first)?
}
""", b"42\n", None,
),
"real_enummap_composed_keys_and_owned_aggregate_values": (
"""
import "@std/meta"
import "@std/enummap"
First :: enum { first, absent }
Second :: enum { last }
Keys :: alias (First | (Second | First))
Item :: struct { values [2]mut i16 }
main proc() i16 {
source Item := { values = [19, 23] }
values :: enummap.init(Keys, Item, { first = source })
source.values[0] = 0
copy := enummap.get(&values, .first)?
copy.values[1] = 0
retained :: enummap.get(&values, .first)?
if (enummap.get(&values, .last) != null or enummap.get(&values, .absent) != null) return -1
return retained.values[0] + retained.values[1]
}
""", b"42\n", None,
),
"real_enummap_all_entries_materialize_at_compile_time": (
"""
import "@std/meta"
import "@std/enummap"
Key :: enum { first, last }
known proc() enummap.EnumMap(Key, i16) {
return enummap.init(Key, i16, { first = 19, last = 23 })
}
main proc() i16 {
values :: $(known())
return enummap.get(&values, .first)? + enummap.get(&values, .last)?
}
""", b"42\n", None,
),
"real_enummap_filled_sparse_constants_preserve_optional_presence": (
"""
import "@std/meta"
import "@std/enummap"
Key :: enum(i16) { absent = -3, present_null = 8, present_value = 21 }
main proc() i16 {
values :: $(enummap.init_default(Key, ?i16, null, {
present_null = some!(null),
present_value = some!(some!(i16(42))),
}))
empty :: $(enummap.init_default(Key, i16, i16(99), {}))
if (enummap.get(&values, .absent) != null or enummap.get(&empty, .absent) != null) return -1
payload :: enummap.get(&values, .present_null)
if (payload == null or payload? != null) return -2
return enummap.get(&values, .present_value)??
}
""", b"42\n", None,
),
"metadata_slices_cross_producers_without_losing_type_identity": (
"""
import "@std/meta"
Id :: distinct i16
Record :: struct { value Id }
retain proc(fields []meta.FieldInfo) []meta.FieldInfo { return fields }
describe_fields proc($T type) []meta.FieldInfo {
return match typeinfo!(T) {
.record |info|: retain(info.fields),
.enum |info|: retain(info.fields),
else: compile_error!("expected fields"),
}
}
Storage proc() type {
source :: describe_fields(Record)
copy := source[0]
copy.type = bool
if (copy.type != bool or source[0].type != Id) return bool
if (describe_fields(struct {}).len != 0) return bool
return struct_type!(.auto, [source[0].name], [source[0].type], [Id(42)])
}
main proc() i16 {
value Storage() :: {}
return i16(value.value)
}
""", b"42\n", None,
),
"composed_enum_metadata_preserves_members_and_sum_identity": (
"""
import "@std/meta"
First :: enum { one, two }
Second :: enum { three }
Keys :: alias (First | (Second | First))
valid proc() bool {
match typeinfo!(Keys) {
.enum |info|: {
if (info.fields.len != 3) return false
inline for info.fields |field, index| {
if (field.index != index or field.type != Keys) return false
selected Keys :: field!(Keys, field.name)
if (index == 0 and selected != .one) return false
if (index == 1 and selected != .two) return false
if (index == 2 and selected != .three) return false
}
return true
}
else: return false,
}
}
main proc() bool { return $(valid()) }
""", b"true\n", None,
),
"inline_metadata_match_keeps_static_tags_and_type_payloads": (
"""
import "@std/meta"
Id :: distinct i16
score proc($T type) i16 {
match typeinfo!(T) {
inline |payload, tag|: {
if (tag == .array) {
if (payload.child == i16) return i16(payload.len)
return 0
} else if (tag == .distinct) {
if (payload == i16) return 40
return 0
} else {
return 0
}
},
}
}
main proc() i16 { return score([2]i16) + score(Id) + score(bool) }
""", b"42\n", None,
),
"active_metadata_payloads_support_direct_checked_projection": (
"""
import "@std/meta"
Id :: distinct i16
Storage proc() type {
if (typeinfo!(Id).distinct != i16) return bool
child :: typeinfo!([2]Id).array.child
count :: typeinfo!([2]Id).array.len
return struct { values [count]child }
}
main proc() i16 {
value Storage() :: { values = [Id(19), Id(23)] }
if (typeinfo!(Storage()).record.fields[0].index != 0) return 0
return i16(value.values[0]) + i16(value.values[1])
}
""", b"42\n", None,
),
}
for name, text, error in (
("missing_argument", "main proc() i16 { typeinfo!()\nreturn 42 }", b"argument count"),
("extra_argument", "main proc() i16 { typeinfo!(i16, bool)\nreturn 42 }", b"argument count"),
("non_type_argument", "main proc() i16 { typeinfo!(42)\nreturn 42 }", b"must name a type"),
(
"overlapping_patterns",
"main proc() i16 { return match typeinfo!(i16) { .integer: 42, .integer: 0, else: 0 } }",
b"duplicate or overlapping match pattern",
),
(
"non_exhaustive_match",
"main proc() i16 { return match typeinfo!(i16) { .integer: 42 } }",
b"match is not exhaustive",
),
(
"void_payload_capture",
"main proc() i16 { return match typeinfo!(i16) { .integer |value|: 42, else: 0 } }",
b"payload capture requires compatible nonvoid tagged union variants",
),
(
"incompatible_payload_capture",
"main proc() i16 { return match typeinfo!(i16) { .array, .record |info|: 42, else: 0 } }",
b"payload capture requires compatible nonvoid tagged union variants",
),
(
"field_bounds",
"""
Bad proc() type {
match typeinfo!(struct { value i16 }) {
.record |info|: return info.fields[1].type,
else: return bool,
}
}
main proc() i16 { value Bad() :: 42
return value }
""",
b"index out of bounds",
),
(
"inactive_metadata_payload_projection",
"main proc() usize { return typeinfo!(i16).array.len }",
b"tagged union field is not active",
),
(
"metadata_slice_elements_remain_readonly",
"""
Bad proc() type {
match typeinfo!(struct { value i16 }) {
.record |info|: {
fields := info.fields
fields[0].type = bool
return fields[0].type
}
else: return bool,
}
}
main proc() Bad() { return 42 }
""",
b"indexed assignment requires a writable array element",
),
(
"runtime_metadata_escape",
"main proc() i16 { info :: typeinfo!(i16)\nreturn 42 }",
b"record fields require a concrete value type",
),
):
cases[name] = ('import "@std/meta"\n' + text, b"", error)
cases["missing_meta_import"] = (
"main proc() i16 { typeinfo!(i16)\nreturn 42 }",
b"", b"typeinfo! requires importing @std/meta",
)
cases["relative_meta_import_is_not_reflection_opt_in"] = (
'import "../std/meta"\nmain proc() i16 { typeinfo!(i16)\nreturn 42 }',
b"", b"typeinfo! requires importing @std/meta",
)
for name, (text, stdout, error) in cases.items():
app = project / name
app.mkdir()
(app / "main.hon").write_text(textwrap.dedent(text).strip() + "\n")
check(app, executable, (stdout, error))
library = project / "library"
library.mkdir()
definition = library / "types.hon"
definition.write_text(textwrap.dedent("""
import "@std/meta"
Record :: struct { value i16 }
Alias :: alias Record
Other :: struct { value i16 }
Child proc($T type) type {
return match typeinfo!(T) {
.record |info|: info.fields[0].type,
else: bool,
}
}
""").strip() + "\n")
app = project / "import_identity"
app.mkdir()
source = app / "main.hon"
source.write_text(textwrap.dedent("""
import "@std/meta"
lib :: import "../library"
Record :: struct { value i16 }
same_record proc($T type) bool {
return match typeinfo!(T) {
.array |info|: info.child == lib.Record and info.child != Record and info.child != lib.Other,
else: false,
}
}
main proc() i16 {
if (!$(same_record([1]lib.Alias))) return -1
value lib.Child(lib.Alias) :: 42
return value
}
""").strip() + "\n")
check(app, executable, (b"42\n", None))
definition.write_text(textwrap.dedent("""
import "@std/meta"
Bad proc() type {
match typeinfo!(struct { value i16 }) {
.record |info|: return info.fields[1].type,
else: return bool,
}
}
""").strip() + "\n")
source.write_text('lib :: import "../library"\nmain proc() lib.Bad() { return 42 }\n')
check(app, executable, (b"", b"index out of bounds"))
diagnosed = run(str(HONEY), "run", str(app))
assert diagnosed.stderr.startswith(f"{definition.resolve()}:4:".encode()), outcome(diagnosed)
assert len(diagnosed.stderr.splitlines()) == 1, outcome(diagnosed)
sibling = project / "sibling_import"
sibling.mkdir()
(sibling / "metadata.hon").write_text('reflection :: import "@std/meta"\n')
(sibling / "main.hon").write_text(
"main proc() i16 { return match typeinfo!(i16) { .integer: 42, else: 0 } }\n"
)
check(sibling, executable, (b"42\n", None))
malformed = project / "malformed"
(malformed / "std" / "meta").mkdir(parents=True)
(malformed / "build.hon").write_text("# project root\n")
metadata = (ROOT / "std/meta/meta.hon").read_text()
(malformed / "std/meta/meta.hon").write_text(metadata.replace(" type type\n", " type usize\n"))
(malformed / "main.hon").write_text(
'import "@std/meta"\n'
"main proc() i16 { return match typeinfo!(i16) { .integer: 42, else: 0 } }\n"
)
check(malformed, executable, (b"", b"@std/meta declarations do not match the compiler reflection ABI"))
return len(cases) + 4
def check_hashmap_packages(temporary, executable):
project = temporary / "hashmap"
project.mkdir()
(project / "build.hon").write_text("# project root\n")
for package in ("std", "ffi"):
(project / package).symlink_to(ROOT / package, target_is_directory=True)
source = project / "main.hon"
# Each growth allocation has distinct typed storage: clearing new entries
# must not overwrite the old entries before the library rehashes them.
source.write_text(textwrap.dedent("""
import "@std/hashmap"
import "@std/mem"
Value :: struct { number i16, items [2]mut i16 }
Slot :: alias hashmap.Entry(i16, Value)
StringSlot :: alias hashmap.Entry([]u8, Value)
State :: struct {
small *mut Slot
medium *mut Slot
large *mut Slot
strings *mut StringSlot
fail bool = false
allocations usize = 0
releases usize = 0
}
allocate proc(context ?@mut anyopaque, size usize, alignment usize) ?*mut u8 {
state @mut State :: ptrcast!(context?)
state.allocations += 1
if (state.fail or alignment != alignof!(Slot)) return null
if (size == sizeof!([8]Slot)) return ptrcast!(state.small)
if (size == sizeof!([16]Slot)) return ptrcast!(state.medium)
if (size == sizeof!([32]Slot)) return ptrcast!(state.large)
if (size == sizeof!([8]StringSlot)) return ptrcast!(state.strings)
return null
}
resize proc(
_ ?@mut anyopaque, _ ?*mut u8, _ usize, _ usize, _ usize,
) ?*mut u8 { return null }
release proc(context ?@mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {
state @mut State :: ptrcast!(context?)
state.releases += 1
}
table mem.AllocatorVTable :: { alloc = allocate, realloc = resize, free = release }
collision_hash proc(key i16) usize { return if (key == 0) 0 else 1 }
equivalent proc(left, right i16) bool {
return left - divtrunc!(left, 100) * 100 == right - divtrunc!(right, 100) * 100
}
exercise proc(allocator mem.Allocator, state @mut State) i16 ! (hashmap.PutError | mem.AllocError) {
map hashmap.HashMap(i16, Value, collision_hash, equivalent) := hashmap.init(allocator)
defer hashmap.deinit(&map)
if (map.count != 0 or map.entries.len != 0 or state.allocations != 0) return -1
if (hashmap.get(&map, 0) != null) return -2
original Value := { number = 0, items = [0, 1] }
try hashmap.put(&map, 0, original)
original.items[0] = 99
if (hashmap.get(&map, 0)?.items[0] != 0) return -3
copy := hashmap.get(&map, 0)?
copy.items[1] = 99
if (hashmap.get(&map, 100)?.items[1] != 1) return -4
duplicate := false
hashmap.put(&map, 100, Value{ number = 999, items = [9, 9] }) catch |err| {
duplicate = err == .key_exists
}
if (!duplicate or map.count != 1 or hashmap.get(&map, 0)?.number != 0) return -7
for (i16(1)..i16(12)) |key| {
try hashmap.put(&map, key, Value{ number = key * 2, items = [key, key + 1] })
}
if (map.count != 12 or map.entries.len != 16) return -5
if (state.allocations != 2 or state.releases != 1) return -6
state.fail = true
previous :: map.entries.ptr
calls :: state.allocations
released :: state.releases
failed := false
hashmap.put(&map, 12, original) catch |err| { failed = err == .out_of_memory }
if (!failed or map.count != 12 or map.entries.len != 16 or map.entries.ptr != previous) return -8
if (state.allocations != calls + 1 or state.releases != released) return -9
if (hashmap.get(&map, 12) != null or hashmap.get(&map, 111)?.number != 22) return -10
state.fail = false
for (i16(12)..i16(24)) |key| {
try hashmap.put(&map, key, Value{ number = key * 2, items = [key, key + 1] })
}
if (map.count != 24 or map.entries.len != 32) return -11
for (i16(0)..i16(24)) |key| {
value :: hashmap.get(&map, key + 100)?
if (value.number != key * 2 or value.items[0] != key or value.items[1] != key + 1) return -12
}
for map.entries |entry| {
if (entry.hash != 0 and entry.hash != 1) return -13
}
if (hashmap.get(&map, 99) != null) return -14
failed = false
hashmap.put(&map, 24, original) catch |err| { failed = err == .out_of_memory }
if (!failed or map.count != 24 or map.entries.len != 32) return -15
if (hashmap.get(&map, 23)?.number != 46 or hashmap.get(&map, 24) != null) return -16
return 42
}
exercise_automatic_and_string_keys proc(allocator mem.Allocator) i16 ! (hashmap.PutError | mem.AllocError) {
automatic hashmap.AutoHashMap(i16, Value) := hashmap.init(allocator)
defer hashmap.deinit(&automatic)
for (i16(0)..i16(12)) |key| {
try hashmap.put(&automatic, key, Value{ number = key, items = [key, key + 1] })
}
edge Value :: { number = 42, items = [19, 23] }
try hashmap.put(&automatic, minval!(i16), edge)
try hashmap.put(&automatic, maxval!(i16), edge)
for (i16(0)..i16(12)) |key| {
value :: hashmap.get(&automatic, key)?
if (value.number != key or value.items[1] != key + 1) return -20
}
if (hashmap.get(&automatic, minval!(i16))?.number != 42
or hashmap.get(&automatic, maxval!(i16))?.items[0] != 19) return -21
if (hashmap.get(&automatic, -1) != null) return -22
strings hashmap.StringHashMap(Value) := hashmap.init(allocator)
defer hashmap.deinit(&strings)
left [3]mut u8 := [97, 0, 98]
right [3]mut u8 := [97, 0, 98]
try hashmap.put(&strings, left[..], edge)
if (hashmap.get(&strings, right[..])?.items[1] != 23) return -23
duplicate := false
hashmap.put(&strings, right[..], Value{ number = 0, items = [0, 0] }) catch |err| {
duplicate = err == .key_exists
}
if (!duplicate or strings.count != 1 or hashmap.get(&strings, left[..])?.number != 42) return -24
try hashmap.put(&strings, "", edge)
if (hashmap.get(&strings, right[..2]) != null or hashmap.get(&strings, "")?.number != 42) return -25
return 42
}
main proc() i16 ! (hashmap.PutError | mem.AllocError) {
small [8]mut Slot := undefined
medium [16]mut Slot := undefined
large [32]mut Slot := undefined
string_storage [8]mut StringSlot := undefined
state State := {
small = (&small).ptr, medium = (&medium).ptr, large = (&large).ptr,
strings = (&string_storage).ptr,
}
allocator mem.Allocator :: { context = &state, vtable = &table }
result :: try exercise(allocator, &state)
if (result != 42) return result
if (state.allocations != 5 or state.releases != 3) return -17
state.fail = true
empty := hashmap.init(i16, Value, collision_hash, equivalent, allocator)
defer hashmap.deinit(&empty)
failed := false
hashmap.put(&empty, 0, Value{ number = 42, items = [4, 2] }) catch |err| {
failed = err == .out_of_memory
}
if (!failed or empty.count != 0 or empty.entries.len != 0) return -18
if (hashmap.get(&empty, 0) != null or state.allocations != 6 or state.releases != 3) return -19
state.fail = false
automatic_result :: try exercise_automatic_and_string_keys(allocator)
if (automatic_result != 42) return automatic_result
if (state.allocations != 10 or state.releases != 7) return -26
return 42
}
""").strip() + "\n")
check(source, executable, (b"42\n", None))
native_cases = (
"""
import "@std/hashmap"
import "@std/mem"
Sparse :: enum(i16) { negative = -7, first = 3, far = 90 }
SparseAlias :: alias Sparse
Inner :: distinct u64
Id :: distinct Inner
integer_keys proc($K type) bool ! (hashmap.PutError | mem.AllocError) {
map hashmap.AutoHashMap(K, usize) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&map)
keys [4]K :: [minval!(K), maxval!(K), K(1), K(2)]
for keys |key, index| { try hashmap.put(&map, key, index) }
for (3..40) |number| { try hashmap.put(&map, K(number), usize(number)) }
if (map.count != 41 or map.entries.len != 64) return false
for keys |key, index| { if (hashmap.get(&map, key)? != index) return false }
for (3..40) |number| {
if (hashmap.get(&map, K(number))? != usize(number)) return false
}
if (hashmap.get(&map, K(40)) != null) return false
if $(minval!(K) < 0) {
try hashmap.put(&map, K(-1), 99)
if (hashmap.get(&map, K(-1))? != 99) return false
}
duplicate := false
hashmap.put(&map, maxval!(K), 999) catch |err| { duplicate = err == .key_exists }
return duplicate and hashmap.get(&map, maxval!(K))? == 1
}
main proc() i16 ! (hashmap.PutError | mem.AllocError) {
if (!try integer_keys(i8) or !try integer_keys(u8)) return -1
if (!try integer_keys(i16) or !try integer_keys(u16)) return -2
if (!try integer_keys(i32) or !try integer_keys(u32)) return -3
if (!try integer_keys(i64) or !try integer_keys(u64)) return -4
if (!try integer_keys(isize) or !try integer_keys(usize)) return -5
flags hashmap.AutoHashMap(bool, i16) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&flags)
try hashmap.put(&flags, false, 19)
try hashmap.put(&flags, true, 23)
if (flags.count != 2 or hashmap.get(&flags, false)? != 19 or hashmap.get(&flags, true)? != 23) return -6
duplicate := false
hashmap.put(&flags, false, 99) catch |err| { duplicate = err == .key_exists }
if (!duplicate or flags.count != 2 or hashmap.get(&flags, false)? != 19) return -7
sparse hashmap.AutoHashMap(SparseAlias, i16) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&sparse)
try hashmap.put(&sparse, .negative, 7)
try hashmap.put(&sparse, .first, 3)
try hashmap.put(&sparse, .far, 90)
if (sparse.count != 3 or hashmap.get(&sparse, Sparse.negative)? != 7) return -8
if (hashmap.get(&sparse, .first)? != 3 or hashmap.get(&sparse, .far)? != 90) return -9
ids hashmap.AutoHashMap(Id, i16) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&ids)
try hashmap.put(&ids, Id(Inner(0)), 19)
try hashmap.put(&ids, Id(Inner(maxval!(u64))), 23)
if (hashmap.get(&ids, Id(Inner(0)))? != 19) return -10
if (hashmap.get(&ids, Id(Inner(maxval!(u64))))? != 23) return -11
if (hashmap.get(&ids, Id(Inner(1))) != null) return -12
return 42
}
""",
"""
import "@std/hashmap"
import "@std/mem"
Padding :: struct_type!(.c, ["tag", "number"], [u8, u64], [null, null])
Row :: struct { values [2]u16 }
Key :: struct { padded Padding, rows [2]Row }
custom_hash proc(_ u16) usize { return 0 }
custom_eql proc(left, right u16) bool {
return left - divtrunc!(left, 100) * 100 == right - divtrunc!(right, 100) * 100
}
main proc() i16 ! (hashmap.PutError | mem.AllocError) {
strings hashmap.StringHashMap(i16) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&strings)
left [3]mut u8 := [97, 0, 98]
right [3]mut u8 := [97, 0, 98]
other [3]mut u8 := [97, 0, 99]
if ((&left).ptr == (&right).ptr) return -7
try hashmap.put(&strings, left[..], 42)
records hashmap.AutoHashMap(Key, i16) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&records)
first Key := { padded = { tag = 7, number = maxval!(u64) }, rows = [{ values = [2, 9] }, { values = [4, 8] }] }
same Key := { padded = { tag = 7, number = maxval!(u64) }, rows = [{ values = [2, 9] }, { values = [4, 8] }] }
first_bytes *mut u8 :: ptrcast!(&first.padded)
same_bytes *mut u8 :: ptrcast!(&same.padded)
if (sizeof!(Padding) != 16 or alignof!(Padding) != 8) return -1
for (usize(1)..usize(8)) |index| {
first_bytes[index] = 17
same_bytes[index] = 238
}
if (first_bytes[1] == same_bytes[1]) return -2
try hashmap.put(&records, first, 19)
if (hashmap.get(&records, same)? != 19) return -3
duplicate := false
hashmap.put(&records, same, 99) catch |err| { duplicate = err == .key_exists }
if (!duplicate or records.count != 1 or hashmap.get(&records, first)? != 19) return -4
reversed :: Key{ padded = { tag = 7, number = maxval!(u64) }, rows = [{ values = [9, 2] }, { values = [4, 8] }] }
swapped :: Key{ padded = { tag = 7, number = maxval!(u64) }, rows = [{ values = [4, 8] }, { values = [2, 9] }] }
try hashmap.put(&records, reversed, 23)
try hashmap.put(&records, swapped, 31)
if (hashmap.get(&records, reversed)? != 23 or hashmap.get(&records, swapped)? != 31) return -5
same.padded.number = 0
if (hashmap.get(&records, same) != null or records.count != 3) return -6
if (hashmap.get(&strings, right[..])? != 42) return -8
if (hashmap.get(&strings, right[..2]) != null or hashmap.get(&strings, other[..]) != null) return -9
duplicate = false
hashmap.put(&strings, right[..], 99) catch |err| { duplicate = err == .key_exists }
if (!duplicate or strings.count != 1 or hashmap.get(&strings, left[..])? != 42) return -10
try hashmap.put(&strings, "", 7)
try hashmap.put(&strings, other[..], 23)
if (strings.count != 3 or hashmap.get(&strings, "")? != 7 or hashmap.get(&strings, other[..])? != 23) return -11
custom hashmap.HashMap(u16, i16, custom_hash, custom_eql) := hashmap.init(mem.c_allocator)
defer hashmap.deinit(&custom)
for (u16(1)..u16(20)) |key| { try hashmap.put(&custom, key, i16(key * 2)) }
for (u16(1)..u16(20)) |key| {
if (hashmap.get(&custom, key + 100)? != i16(key * 2)) return -12
}
duplicate = false
hashmap.put(&custom, 101, 999) catch |err| { duplicate = err == .key_exists }
if (!duplicate or custom.count != 19 or hashmap.get(&custom, 1)? != 2) return -13
if (hashmap.get(&custom, 99) != null) return -14
return 42
}
""",
)
for text in native_cases:
source.write_text(textwrap.dedent(text).strip() + "\n")
interpreted = run(str(HONEY), "run", str(source))
assert interpreted.returncode == 1 and interpreted.stdout == b"", outcome(interpreted)
assert b"foreign function calls are unsupported by the interpreter" in interpreted.stderr, outcome(interpreted)
assert len(interpreted.stderr.splitlines()) == 1, outcome(interpreted)
for optimization in ("-O0", "-O2"):
built = run(str(HONEY), "build", str(source), "-o", str(executable), optimization)
assert outcome(built) == (0, b"", b""), outcome(built)
assert outcome(run(str(executable))) == (0, b"42\n", b""), optimization
executable.unlink()
invalid_keys = (("f64", "f64(1)"), ("[]u8", '"abc"'), ("?i16", "some!(i16(1))"))
for key_type, key in invalid_keys:
source.write_text(textwrap.dedent(f"""
import "@std/hashmap"
import "@std/mem"
main proc() bool {{
map := hashmap.init({key_type}, i16, null, null, mem.c_allocator)
return hashmap.get(&map, {key}) == null
}}
""").strip() + "\n")
check(source, executable, (
b"true\n",
b"AutoHashMap key requires integers, booleans, enums, distinct types, arrays or records",
))
return 1 + len(invalid_keys), len(native_cases)
def main():
with tempfile.TemporaryDirectory(prefix="honey native ' ; $") as directory:
temporary = Path(directory)
executable = temporary / "program ' ; $"
count = 0
for source in sorted((ROOT / "programs").glob("*.hon")):
check(source, executable)
count += 1
for name, (text, stdout, error) in CASES.items():
source = temporary / f"{name}.hon"
source.write_text(textwrap.dedent(text).strip() + "\n")
check(source, executable, (stdout, error))
count += 1
allocator_count = check_allocator_libc(temporary, executable)
arraylist_count, arraylist_native_count = check_arraylist_packages(temporary, executable)
count += arraylist_count
hashmap_count, hashmap_native_count = check_hashmap_packages(temporary, executable)
count += hashmap_count
count += check_packages(temporary, executable)
count += check_namespace_packages(temporary, executable)
count += check_record_packages(temporary, executable)
count += check_data_model_packages(temporary, executable)
count += check_specialization_packages(temporary, executable)
count += check_typeinfo_packages(temporary, executable)
count += check_fallible_packages_and_entry(temporary, executable)
count += check_dependency_provenance(temporary, executable)
source = ROOT / "programs/factorial.hon"
emitted = run(str(HONEY), "emit-llvm", str(source))
assert emitted.returncode == 0 and emitted.stderr == b"", outcome(emitted)
ir = temporary / "factorial.ll"
ir.write_bytes(emitted.stdout)
assembled = run("clang", str(ir), "-o", str(executable))
assert assembled.returncode == 0, outcome(assembled)
assert outcome(run(str(executable))) == (0, b"120\n", b"")
executable.unlink()
missing_compiler = run(
str(HONEY), "build", str(source), "-o", str(executable),
env={**os.environ, "PATH": str(temporary)},
)
assert missing_compiler.returncode == 2, outcome(missing_compiler)
assert b"cannot start native compiler" in missing_compiler.stderr, outcome(missing_compiler)
assert not executable.exists()
invalid = run(str(HONEY), "build", str(source), "-o", str(executable), "-O3")
assert invalid.returncode == 2 and b"usage:" in invalid.stderr, outcome(invalid)
print(f"{count} programs matched interpreter at -O0 and -O2; {allocator_count + arraylist_native_count + hashmap_native_count} native allocator programs, LLVM output and CLI errors passed")
if __name__ == "__main__":
main()