Files
honey/tests/native.py
T

8667 lines
320 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 = {
"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",
),
"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,
),
"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, []u8 } { return {42, "borrowed"} }
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_rejects_borrowed_element_escape": (
"""
data proc() [1][]u8 { return ["borrowed"] }
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_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_rejects_slice_escape": (
"""
make proc() [1][]u8 { return ["borrowed"] }
main proc() usize { return $(make())[0].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_remains_an_escape_trap": (
"""
Storage :: union { number i16, bits u16 }
make proc() Storage { return Storage { number = 42 } }
main proc() i16 { return $(make()).number }
""", b"", b"compile-time result cannot escape evaluation",
),
"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",
),
}
# 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}_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)
return 22
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 `
}
""", 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,
),
"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 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
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} native allocator programs, LLVM output and CLI errors passed")
if __name__ == "__main__":
main()