cc39c96fc0
Snapshot full union storage rather than choosing an overlapping field. Preserve structural union source syntax independently of nominal identity so direct literal arguments materialize and share normalized specialization keys. Reject uninitialized bytes and address-bearing member layouts.
1069 lines
48 KiB
Plaintext
1069 lines
48 KiB
Plaintext
import "@std/mem"
|
|
import "@std/arraylist"
|
|
import "@std/testing"
|
|
import "@source/ast"
|
|
import "@source/diagnostics"
|
|
import "@source/ir"
|
|
import "@source/interpreter"
|
|
|
|
@hide:file
|
|
owned_text proc(text []u8) arraylist.ArrayList(u8) ! mem.AllocError {
|
|
bytes := arraylist.init(u8, mem.c_allocator)
|
|
errdefer arraylist.deinit(&bytes)
|
|
try arraylist.reserve(&bytes, text.len)
|
|
for (text) |byte| try arraylist.append(&bytes, byte)
|
|
return bytes
|
|
}
|
|
|
|
keeps_package_declarations_distinct_and_ir_independent test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
first := try owned_text("value :: 21\nmain proc() int { return value * 2 }")
|
|
defer arraylist.deinit(&first)
|
|
second := try owned_text("value :: 3\nmain proc() int { return value * 2 }")
|
|
defer arraylist.deinit(&second)
|
|
sibling := try owned_text("helper proc() int { return 7 }")
|
|
defer arraylist.deinit(&sibling)
|
|
path [9]mut u8 := undefined
|
|
memcopy!(path[..], "first.hon")
|
|
session := init(mem.c_allocator)
|
|
# the IR must outlive the compilation, including source buffers and interned names.
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
left :: try add_source(&session, root, path[..], &first, &diagnostic_store)
|
|
right :: try add_source(&session, dependency, "second.hon", &second, &diagnostic_store)
|
|
third :: try add_source(&session, root, "sibling.hon", &sibling, &diagnostic_store)
|
|
path[0] = 'X'
|
|
try testing.expect_equal(0, first.capacity)
|
|
try testing.expect_equal(0, first.items.len)
|
|
try testing.expect(mem.eql(source(&session, left).path, "first.hon"))
|
|
try testing.expect_equal(root, source(&session, left).package)
|
|
try testing.expect_equal(dependency, source(&session, right).package)
|
|
try testing.expect_equal(root, source(&session, third).package)
|
|
try testing.expect_equal(left, session.packages.items[usize(root)].sources.items[0])
|
|
try testing.expect_equal(third, session.packages.items[usize(root)].sources.items[1])
|
|
a :: declaration(&session, left, 0)
|
|
b :: declaration(&session, right, 0)
|
|
try testing.expect(a.source != b.source)
|
|
tree :: ast.view(&session.builder, source(&session, left).root)
|
|
try testing.expect_equal(ast.name_id(&tree, a.node), ast.name_id(&tree, b.node))
|
|
try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, a.node).span), "value :: 21"))
|
|
try testing.expect(mem.eql(ast.source_text(&tree, ast.statement_decl(&tree, b.node).span), "value :: 3"))
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, dependency, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
left_result := try interpreter.run(mem.c_allocator, &modules[0], &diagnostic_store)
|
|
defer interpreter.deinit(&left_result)
|
|
right_result := try interpreter.run(mem.c_allocator, &modules[1], &diagnostic_store)
|
|
defer interpreter.deinit(&right_result)
|
|
try testing.expect(left_result.trap == null and right_result.trap == null)
|
|
try testing.expect_equal(i64(42), left_result.value.data.integer)
|
|
try testing.expect_equal(i64(6), right_result.value.data.integer)
|
|
}
|
|
|
|
recompiles_specialized_calls_without_borrowing_previous_ir test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`identity proc($T type, value T) T {
|
|
` if (T == i16) return value else return value.missing
|
|
`}
|
|
`Box proc(T type) type { return struct { value T } }
|
|
`make_box proc($T type) Box(T) { return { value = 40 } }
|
|
`count proc() usize {
|
|
` result := 0
|
|
` while (result < 2) result = result + 1
|
|
` return result
|
|
`}
|
|
`Fixed proc(N usize) type {
|
|
` Element := i8
|
|
` length usize := 0
|
|
` while (length < N) {
|
|
` match length { 0: Element = i16, else: Element = i16 }
|
|
` length = length + 1
|
|
` }
|
|
` return match length {
|
|
` 2: struct {
|
|
` values [match length { 2: length, else: usize(1) }](match true {
|
|
` true: Element,
|
|
` false: i8(128),
|
|
` })
|
|
` bias i16 = match true { true: 0, false: i8(128) }
|
|
` },
|
|
` else: i8(128),
|
|
` }
|
|
`}
|
|
`data proc() [2]i16 { return [40, 2] }
|
|
`Tag :: enum(i16) { empty = -7, payload = 90 }
|
|
`Choice :: union(Tag) { payload struct { values [2]i16, text string }, empty void }
|
|
`Error :: union(enum) { failed struct { code i16, text string } }
|
|
`Packet :: struct { choices [2]Choice, results [2](i16 ! Error) }
|
|
`packet_data proc() Packet {
|
|
` return {
|
|
` choices = [.payload { values = [40, 2], text = "ok" }, .empty],
|
|
` results = [40, .failed { code = 2, text = "owned" }],
|
|
` }
|
|
`}
|
|
`Token proc($value Packet) type { return struct {} }
|
|
`Captured proc(choice Choice) type {
|
|
` match choice {
|
|
` .payload |detail|: return struct {
|
|
` values [match detail.text.len { 2: usize(2), else: usize(0) }]i16
|
|
` bias i16 = match choice { .payload |selected|: selected.values[1], .empty: 0 }
|
|
` },
|
|
` .empty: return bool,
|
|
` }
|
|
`}
|
|
`Optional proc() type {
|
|
` pending ?usize := 2
|
|
` Result := i8
|
|
` while pending |length| {
|
|
` pending = null
|
|
` Result = [length]i16
|
|
` }
|
|
` return Result
|
|
`}
|
|
`Updated proc() type {
|
|
` config struct { counts [2]mut usize, bias i16 } := { counts = [0, 0], bias = 0 }
|
|
` original :: config
|
|
` for (usize(0)..2) |index| {
|
|
` field!(config, "counts")[index] = index + 1
|
|
` field!(config, "bias") = field!(config, "bias") + 21
|
|
` }
|
|
` return struct {
|
|
` values [config.counts[1]]i16
|
|
` bias i16 = config.bias + i16(original.counts[1])
|
|
` }
|
|
`}
|
|
`Collected proc() type {
|
|
` counts [2]mut usize := [1, 1]
|
|
` length usize := 0
|
|
` for counts |amount, index| {
|
|
` counts[1] = 2
|
|
` length = length + amount
|
|
` if (index == 0) continue
|
|
` }
|
|
` Element := i8
|
|
` for "ok" |byte| { if (byte == u8(107)) Element = i16 }
|
|
` return [length]Element
|
|
`}
|
|
`TypeArray proc() type {
|
|
` types [2]mut [1]mut type := [[i8], [bool]]
|
|
` original :: types
|
|
` for types |row, index| {
|
|
` copied := row
|
|
` copied[0] = u8
|
|
` if (row[0] == u8) return bool
|
|
` if (index == 0) { (types[1])[0] = i16 }
|
|
` if (index == 1 and row[0] != i16) return bool
|
|
` }
|
|
` if (original[1][0] != bool) return bool
|
|
` inferred := [[i8], [bool]]
|
|
` inferred = [[i16], [u8]]
|
|
` empty [0]type :: []
|
|
` for (empty) |_| return bool
|
|
` return struct { values [types.len]types[1][0], bias inferred[0][0] = 2 }
|
|
`}
|
|
`TypeRows proc() [2]mut [1]mut type {
|
|
` rows [2]mut [1]mut type := [[i8], [i16]]
|
|
` (rows[0])[0] = i16
|
|
` return rows
|
|
`}
|
|
`copy_type_rows proc(rows [2]mut [1]mut type) [2]mut [1]mut type {
|
|
` copied := rows
|
|
` (copied[0])[0] = u8
|
|
` if (rows[0][0] != i16) return [[bool], [bool]]
|
|
` return copied
|
|
`}
|
|
`BoundaryType proc(rows [2]mut [1]mut type) type {
|
|
` original :: rows
|
|
` changed :: copy_type_rows(rows)
|
|
` if (changed[0][0] != u8 or rows[0][0] != i16 or original[0][0] != i16) return bool
|
|
` return struct { values [rows.len]rows[0][0], bias rows[1][0] = 2 }
|
|
`}
|
|
`read_type_rows proc($rows [2]mut [1]mut type, value rows[0][0]) rows[1][0] {
|
|
` return value + rows[1][0](rows.len)
|
|
`}
|
|
`UninitializedRows proc() [2]mut type {
|
|
` types [2]mut type := undefined
|
|
` for (usize(0)..types.len) |index| {
|
|
` if (index == 0) { types[index] = struct { value i16 } }
|
|
` else { types[index] = types[0] }
|
|
` }
|
|
` return types
|
|
`}
|
|
`UninitializedType proc(types [2]mut type) type {
|
|
` return struct { first types[0], second types[1] }
|
|
`}
|
|
`UninitializedValues proc() type {
|
|
` rows [2]mut [2]mut usize := undefined
|
|
` (rows[0])[0] = 1
|
|
` copied := rows
|
|
` rows[0] = [3, 4]
|
|
` (copied[0])[1] = 2
|
|
` copied[1] = [1, 1]
|
|
` for (usize(0)..rows[1].len) |index| { (rows[1])[index] = index + 1 }
|
|
` return struct {
|
|
` values [copied[0][1]]i16
|
|
` bias i16 = i16(copied[1][0] + rows[1][0])
|
|
` }
|
|
`}
|
|
`TypeRecord proc() type {
|
|
` Config :: struct { child type, counts [2]mut usize, bias i16 = 2 }
|
|
` config Config := { child = i8, counts = [0, 0] }
|
|
` original :: config
|
|
` config.child = i16
|
|
` for config.counts |_, index| { config.counts[index] = index + 1 }
|
|
` if (original.child != i8 or original.counts[1] != 0) return bool
|
|
` return struct { values [config.counts[1]]config.child, bias i16 = config.bias }
|
|
`}
|
|
`BoundaryConfig :: struct { child type, counts [2]mut usize, bias i16 = 2 }
|
|
`record_config proc() BoundaryConfig { return { child = i16, counts = [1, 2] } }
|
|
`change_record_config proc(input BoundaryConfig) BoundaryConfig {
|
|
` copied := input
|
|
` copied.child = u8
|
|
` copied.counts[1] = 3
|
|
` return copied
|
|
`}
|
|
`RecordBoundary proc(input BoundaryConfig) type {
|
|
` changed :: change_record_config(input)
|
|
` if (input.child != i16 or input.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 }
|
|
`}
|
|
`RecordAlias :: alias RecordBoundary(record_config())
|
|
`read_record_config proc($input BoundaryConfig, value input.child) input.child {
|
|
` return value + input.bias
|
|
`}
|
|
`record_pair proc() struct { type, usize } { return {i16, 2} }
|
|
`RecordPairElement proc(input struct { type, usize }) type { return field!(input, "0") }
|
|
`read_record_pair proc($input struct { type, usize }, value RecordPairElement(input)) RecordPairElement(input) {
|
|
` return value + i16(field!(input, "1"))
|
|
`}
|
|
`read_selected proc($choice Choice, value i16) i16 {
|
|
` match choice {
|
|
` .payload |detail|: {
|
|
` copied :: detail
|
|
` if (copied.text.len != 2) return -1
|
|
` return match detail.values[1] {
|
|
` 2: match true { true: value + detail.values[1], false: value.missing },
|
|
` else: value.missing,
|
|
` }
|
|
` }
|
|
` .empty: return value.missing,
|
|
` }
|
|
`}
|
|
`main proc() i16 {
|
|
` if $(i16 != i16) { return $(i8(128)) }
|
|
` values :: $(data())
|
|
` box Box(i16) :: make_box()
|
|
` inferred i16 :: identity(40)
|
|
` if (inferred != box.value) return 0
|
|
` fixed Fixed(count()) :: { values = [box.value, 2] }
|
|
` same Fixed(2) :: fixed
|
|
` packet :: $(packet_data())
|
|
` if (Token(packet_data()) != Token(packet)) return 0
|
|
` captured Captured(packet.choices[0]) :: { values = [19, 21] }
|
|
` if (captured.values[0] + captured.values[1] + captured.bias != 42) return 0
|
|
` optional Optional() :: captured.values
|
|
` if (optional[0] + optional[1] != 40) return 0
|
|
` updated Updated() :: { values = optional }
|
|
` if (updated.bias != 42 or updated.values[1] != 21) return 0
|
|
` collected Collected() :: [19, 21, 2]
|
|
` same_collected Collected() :: collected
|
|
` total i16 := 0
|
|
` for same_collected |item| { total = total + item }
|
|
` if (total != 42) return 0
|
|
` type_array TypeArray() :: { values = [19, 21] }
|
|
` same_type_array TypeArray() :: type_array
|
|
` if (same_type_array.values[0] + same_type_array.values[1] + same_type_array.bias != 42) return 0
|
|
` boundary BoundaryType(TypeRows()) :: { values = [19, 21] }
|
|
` same_boundary BoundaryType(TypeRows()) :: boundary
|
|
` if (same_boundary.values[0] + same_boundary.values[1] + field!(same_boundary, "bias") != 42) return 0
|
|
` if (copy_type_rows(TypeRows())[0][0] != u8 or copy_type_rows(TypeRows())[1][0] != i16) return 0
|
|
` if (TypeRows()[0][0] != i16) return 0
|
|
` if (read_type_rows(TypeRows(), 40) != 42 or read_type_rows(TypeRows(), 40) != 42) return 0
|
|
` initialized UninitializedType(UninitializedRows()) :: {
|
|
` first = { value = 19 }, second = { value = 21 },
|
|
` }
|
|
` same_initialized UninitializedType(UninitializedRows()) :: initialized
|
|
` copied_initialized := same_initialized.first
|
|
` initialized_values UninitializedValues() :: { values = [19, 21] }
|
|
` same_initialized_values UninitializedValues() :: initialized_values
|
|
` if (same_initialized_values.values[0] + same_initialized_values.values[1] + same_initialized_values.bias != 42) return 0
|
|
` type_record TypeRecord() :: { values = [19, 21] }
|
|
` same_type_record TypeRecord() :: type_record
|
|
` if (same_type_record.values[0] + same_type_record.values[1] + same_type_record.bias != 42) return 0
|
|
` record_boundary RecordAlias :: { values = [19, 21] }
|
|
` same_record_boundary RecordBoundary({ child = i16, counts = [1, 2] }) :: record_boundary
|
|
` if (same_record_boundary.values[0] + same_record_boundary.values[1] + same_record_boundary.bias != 42) return 0
|
|
` if (read_record_config(record_config(), 40) != 42) return 0
|
|
` if (read_record_pair(record_pair(), 40) != 42 or read_record_pair(record_pair(), 40) != 42) return 0
|
|
` copied_initialized = same_initialized.second
|
|
` payload :: packet.choices[0].payload
|
|
` if (payload.values[0] != 40 or payload.values[1] != 2 or payload.text.len != 2) return 0
|
|
` match packet.choices[1] { .empty: {}, .payload: return 0 }
|
|
` if ((packet.results[0] catch 0) != 40) return 0
|
|
` error_code :: packet.results[1] catch |err| match err {
|
|
` .failed |detail|: detail.code + i16(detail.text.len),
|
|
` }
|
|
` if (error_code != 7) return 0
|
|
` return read_selected(packet.choices[0], identity(initialized.first.value) + copied_initialized.value + same.values[$(usize(1))] + same.bias - 2)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "generic.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
recompiles_imported_inline_for_without_retaining_expansions test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`dep :: import "../dependency"
|
|
`touch proc(value i16) i16 { return value }
|
|
`main proc() i16 {
|
|
` total i16 := 0
|
|
` inline for dep.values() |value, index| {
|
|
` at usize :: index
|
|
` total = total + touch(value) + i16(at)
|
|
` }
|
|
` inline for dep.types() |T| {
|
|
` if (T == i16) {
|
|
` value T :: total
|
|
` total = touch(value)
|
|
` } else {
|
|
` value T :: true
|
|
` if (!value) return 0
|
|
` }
|
|
` }
|
|
` inline for dep.metadata() |item, index| {
|
|
` if (index == 0) {
|
|
` if (item != i16) return 0
|
|
` } else if (index == 1) {
|
|
` exact i8 :: item
|
|
` if (exact != 42) return 0
|
|
` } else if (item.len != 2) return 0
|
|
` }
|
|
` inline for (i8(0)..i8(2)) |outer| {
|
|
` inline for [i8(0), i8(1)] |inner| {
|
|
` for (0..usize(2)) |index| {
|
|
` if (index == 0) continue
|
|
` total = total + i16(outer + inner)
|
|
` }
|
|
` }
|
|
` }
|
|
` return total
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`values proc() [2]i16 { return [17, 20] }
|
|
`types proc() [2]type { return [i16, bool] }
|
|
`metadata proc() struct { type, i8, string } { return {i16, 42, "ok"} }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/values.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_imported_inline_match_arms_without_retaining_expansions test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`dep :: import "../dependency"
|
|
`known proc($tag dep.Mode) i16 {
|
|
` if (tag == .answer) return 0 else return false
|
|
`}
|
|
`enum_score proc(input dep.Mode) i16 {
|
|
` return match input { .skip: 0, inline |tag|: known(tag) }
|
|
`}
|
|
`main proc() i16 {
|
|
` values :: dep.values()
|
|
` if (enum_score(.skip) + enum_score(dep.mode()) != 0) return -1
|
|
` if (dep.error_score(.Failure{code = 42}) + dep.error_score(.missing) != 42) return -2
|
|
` return (
|
|
` dep.read(dep.Choice, values[0]) + dep.read(dep.Choice, values[1])
|
|
` + dep.read(dep.Choice, values[2]) + dep.read(dep.Choice, values[3])
|
|
` )
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`Mode :: enum(i16) { skip = -7, answer = 42 }
|
|
`Tag :: enum(i16) { number = -7, record = 3, text = 42, empty = 90 }
|
|
`Pair :: struct { values [2]i16 }
|
|
`Choice :: union(Tag) { text string, empty void, number i8, record Pair }
|
|
`Missing :: enum { missing }
|
|
`Failure :: struct { code i16 }
|
|
`Errors :: alias (Missing | Failure | Missing)
|
|
`fail proc(input Errors) i16 ! Errors { return input }
|
|
`error_score proc(input Errors) i16 {
|
|
` return fail(input) catch |err| match err {
|
|
` inline |payload, tag|: match tag { .Failure: payload.code, else: 0 },
|
|
` }
|
|
`}
|
|
`mode proc() Mode { return .answer }
|
|
`values proc() [4]Choice {
|
|
` return [.number{19}, .record{values = [9, 11]}, .text{"ok"}, .empty]
|
|
`}
|
|
`narrow proc(value i8) i16 { return i16(value) }
|
|
`pair proc(value Pair) i16 { return value.values[0] + value.values[1] }
|
|
`read proc($T type, input T) i16 {
|
|
` match input {
|
|
` inline |payload, tag|: {
|
|
` match tag {
|
|
` inline |selected|: {
|
|
` if (selected == .number) { return narrow(payload) }
|
|
` else if (selected == .record) { return pair(payload) }
|
|
` else if (selected == .text) { return i16(payload.len) }
|
|
` else {
|
|
` payload
|
|
` return 1
|
|
` }
|
|
` },
|
|
` }
|
|
` },
|
|
` }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/values.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_generated_records_without_borrowing_previous_ir test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`Child proc(value i16) type {
|
|
` return struct_type!(.auto, ["value"], [i16], [value])
|
|
`}
|
|
`Parent proc(value i16) type {
|
|
` ChildType :: Child(value)
|
|
` child ChildType :: {}
|
|
` return struct_type!(
|
|
` .auto,
|
|
` ["child", "bias", "text"],
|
|
` [ChildType, i16, string],
|
|
` [child, 2, "owned"],
|
|
` )
|
|
`}
|
|
`Captured proc(value ?i16) type {
|
|
` return if value |payload| struct { value i16 = payload } else bool
|
|
`}
|
|
`selected proc($value ?i16) i16 {
|
|
` return if $(value) |payload| payload else 7
|
|
`}
|
|
`main proc() i16 {
|
|
` parent Parent(40) :: {}
|
|
` captured Captured(40) :: {}
|
|
` absent Captured(null) :: false
|
|
` if (absent or captured.value != selected(40) or selected(null) != 7) return 0
|
|
` same Parent(40) :: parent
|
|
` child Child(40) :: same.child
|
|
` if (Child(40) == Child(41) or Parent(40) == Parent(41)) return 0
|
|
` other Parent(41) :: {}
|
|
` if (other.child.value != 41 or same.text.len != 5) return 0
|
|
` return child.value + same.bias
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "generated.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
recompiles_imported_typeinfo_without_borrowing_metadata test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
metadata :: try add_package(&session)
|
|
root_bytes := try owned_text(
|
|
`meta :: import "@std/meta"
|
|
`Id :: distinct i16
|
|
`Keys :: enum { left, right }
|
|
`Source :: struct { value Id }
|
|
`describe proc($T type) meta.TypeInfo { return typeinfo!(T) }
|
|
`identity proc($T type, value T) T { return value }
|
|
`Storage proc() type {
|
|
` match describe(Keys) {
|
|
` .enum |info|: {
|
|
` names [info.fields.len]mut []u8 := undefined
|
|
` types [info.fields.len]mut type := undefined
|
|
` defaults [info.fields.len]mut ?Id := undefined
|
|
` inline for info.fields |field, index| {
|
|
` if (field.index != index or field.type != Keys) compile_error!("invalid enum field")
|
|
` names[index] = field.name
|
|
` types[index] = Id
|
|
` defaults[index] = Id(40)
|
|
` }
|
|
` return struct_type!(.auto, names, types, defaults)
|
|
` }
|
|
` else: compile_error!("expected enum")
|
|
` }
|
|
`}
|
|
`main proc() i16 {
|
|
` match describe([2]Id) {
|
|
` .array |info|: {
|
|
` if (info.child != Id or info.len != 2) return 0
|
|
` }
|
|
` else: return 0
|
|
` }
|
|
` match describe(Id) {
|
|
` .distinct |backing|: if (backing != i16) return 0
|
|
` else: return 0
|
|
` }
|
|
` match describe(Source) {
|
|
` .record |info|: {
|
|
` if (info.fields.len != 1 or info.is_tuple or info.layout != .auto) return 0
|
|
` inline for info.fields |field, index| {
|
|
` if (field.type != Id or field.index != index or field.name.len != 5) return 0
|
|
` }
|
|
` }
|
|
` else: return 0
|
|
` }
|
|
` storage Storage() :: {}
|
|
` left Id :: identity(Id, storage.left)
|
|
` right Id :: identity(Id, storage.right)
|
|
` return i16(left) + i16(right) - 38
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&root_bytes)
|
|
metadata_bytes := try owned_text(
|
|
`Layout :: enum { auto, c }
|
|
`ArrayInfo :: struct { child type, len usize }
|
|
`FieldInfo :: struct { name []u8, type type, index usize }
|
|
`RecordInfo :: struct { name ?[]u8, fields []FieldInfo, is_tuple bool, layout Layout }
|
|
`EnumInfo :: struct { fields []FieldInfo }
|
|
`TypeInfo :: union(enum) {
|
|
` invalid void
|
|
` void void
|
|
` noreturn void
|
|
` anyopaque void
|
|
` bool void
|
|
` integer void
|
|
` float void
|
|
` array ArrayInfo
|
|
` pointer void
|
|
` slice void
|
|
` range void
|
|
` optional void
|
|
` function void
|
|
` enum EnumInfo
|
|
` record RecordInfo
|
|
` union void
|
|
` fallible void
|
|
` distinct type
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&metadata_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, metadata, "std/meta/meta.hon", &metadata_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = metadata,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for (0..modules.len) |index| {
|
|
outcome := try interpreter.run(mem.c_allocator, &modules[index], &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
}
|
|
|
|
dependency_traps_keep_original_spans_and_remain_demand_driven test {
|
|
mains [2][]u8 :: [
|
|
`dep :: import "../dependency"
|
|
`main proc() int { return dep.fail(false) }
|
|
`
|
|
,
|
|
`dep :: import "../dependency"
|
|
`main proc() int { return dep.fail(true) }
|
|
`
|
|
,
|
|
]
|
|
prefix ::
|
|
`
|
|
`fail proc(take bool) int {
|
|
` if take {
|
|
`
|
|
for (mains) |main, index| {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
module ir.Module := undefined
|
|
dependency_source SourceId := undefined
|
|
original diagnostics.DiagnosticId := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(main)
|
|
defer arraylist.deinit(&root_bytes)
|
|
dependency_bytes := try owned_text(
|
|
`
|
|
`fail proc(take bool) int {
|
|
` if take {
|
|
` return missing
|
|
` }
|
|
` return 42
|
|
`}
|
|
`
|
|
,
|
|
)
|
|
defer arraylist.deinit(&dependency_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
dependency_source = try add_source(&session, dependency, "dependency/fail.hon", &dependency_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
module = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&module)
|
|
try testing.expect_equal(1, diagnostics.count(&diagnostic_store))
|
|
original = diagnostics.DiagnosticId(0)
|
|
diagnostic :: diagnostics.get(&diagnostic_store, original)?
|
|
try testing.expect_equal(diagnostics.Code.unknown_name, diagnostic.code)
|
|
try testing.expect_equal(dependency_source, diagnostic.span.source)
|
|
start :: u32(prefix.len + " return ".len)
|
|
try testing.expect_equal(start, diagnostic.span.start)
|
|
try testing.expect_equal(start + 7, diagnostic.span.end)
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect_equal(1, diagnostics.count(&diagnostic_store))
|
|
if (index == 0) {
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
} else {
|
|
try testing.expect_equal(original, outcome.trap?)
|
|
}
|
|
}
|
|
}
|
|
|
|
file_local_declarations_are_isolated_from_siblings_and_import_selection test {
|
|
callers [4][]u8 :: [
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.answer() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.sibling() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.leak() }\n",
|
|
"dep :: import \"../dependency\"\nmain proc() int { return dep.helper() }\n",
|
|
]
|
|
for callers |caller, index| {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
root_bytes := try owned_text(caller)
|
|
defer arraylist.deinit(&root_bytes)
|
|
first_bytes := try owned_text(
|
|
`@hide:file
|
|
`helper proc() int { return 42 }
|
|
`@hide:file secret :: 7
|
|
`answer proc() int { return helper() }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&first_bytes)
|
|
second_bytes := try owned_text(
|
|
`@hide:file
|
|
`helper proc() int { return 99 }
|
|
`sibling proc() int { return helper() }
|
|
`leak proc() int { return secret }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&second_bytes)
|
|
root_source :: try add_source(&session, root, "app/main.hon", &root_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/first.hon", &first_bytes, &diagnostic_store)
|
|
_ = try add_source(&session, dependency, "dependency/second.hon", &second_bytes, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
module := try compile(&session, root, &diagnostic_store)
|
|
defer ir.deinit(&module)
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
if (index < 2) {
|
|
try testing.expect(outcome.trap == null)
|
|
expected :: if (index == 0) i64(42) else i64(99)
|
|
try testing.expect_equal(expected, outcome.value.data.integer)
|
|
} else {
|
|
diagnostic :: diagnostics.get(&diagnostic_store, outcome.trap?)?
|
|
try testing.expect_equal(diagnostics.Code.unknown_name, diagnostic.code)
|
|
}
|
|
}
|
|
}
|
|
|
|
yielding_blocks_recompile_owned_constants_and_generated_types test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`Choose proc(wide bool) type {
|
|
` return { Selected := i8
|
|
` if (wide) Selected = i16
|
|
` yield Selected }
|
|
`}
|
|
`Box proc(wide bool) type {
|
|
` return struct { value Choose(wide) = { yield 42 } }
|
|
`}
|
|
`compute proc() i16 {
|
|
` return { value i16 := 40
|
|
` defer value = 0
|
|
` yield value + 2 }
|
|
`}
|
|
`main proc() i16 {
|
|
` value Box(true) :: {}
|
|
` constant :: $(compute())
|
|
` return { yield if (constant == value.value) constant else -1 }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "yielding.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
compound_updates_and_type_composition_recompile_without_retaining_rewrites test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`A :: enum { first }
|
|
`B :: enum { second }
|
|
`Errors :: A | B
|
|
`Box proc() type {
|
|
` counts [1]mut usize := [1]
|
|
` counts[0] <<= 1
|
|
` return struct { values [counts[0]]i16 }
|
|
`}
|
|
`compute proc() u8 {
|
|
` value u8 := 21
|
|
` value <<= 1
|
|
` return value
|
|
`}
|
|
`main proc() i16 {
|
|
` box Box() :: { values = [40, 2] }
|
|
` answer i16 := i16($(compute()))
|
|
` answer xor= box.values[0] + box.values[1]
|
|
` return answer + 42
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
_ = try add_source(&session, root, "operators.hon", &bytes, &diagnostic_store)
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_callbacks_recompile_without_retaining_interpreter_function_ids test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`increment proc(value i16) i16 { return value + 100 }
|
|
`main proc() i16 {
|
|
` callback :: $(lib.choose())
|
|
` return callback(41)
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/callbacks/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Callback :: alias @proc(value i16) i16
|
|
`bias i16 :: 1
|
|
`@hide:file
|
|
`increment proc(value i16) i16 { return value + bias }
|
|
`choose proc() Callback { return increment }
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/callbacks/library/callback.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_byte_slices_recompile_without_borrowing_evaluation_storage test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`main proc() i16 {
|
|
` packet :: $(lib.make())
|
|
` if (packet.bytes.len != 4 or packet.suffix.len != 3) return -1
|
|
` if (packet.bytes[0] != 255 or packet.bytes[1] != 0) return -2
|
|
` if (packet.bytes[2] != 128 or packet.bytes[3] != 42) return -3
|
|
` if (packet.suffix[0] != 65 or packet.suffix[1] != 0) return -4
|
|
` if (packet.suffix[2] != 66 or packet.suffix.ptr[3] != 0) return -5
|
|
` if (packet.marked.len != 2 or packet.marked.ptr[2] != 255) return -6
|
|
` if (packet.marked[0] != 40 or packet.marked[1] != 2) return -7
|
|
` return 42
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/byte_slices/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Packet :: struct { bytes []u8, suffix [;0]u8, marked [;255]u8 }
|
|
`make proc() Packet {
|
|
` bytes [4]mut u8 := undefined
|
|
` bytes[0] = 255
|
|
` bytes[1] = 0
|
|
` bytes[2] = 128
|
|
` bytes[3] = 42
|
|
` marked [3]mut u8 := [40, 2, 255]
|
|
` return Packet { bytes = bytes[..], suffix = "xA\0B"[1..;0], marked = marked[..2;255] }
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/byte_slices/library/bytes.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|
|
|
|
computed_untagged_unions_recompile_without_borrowing_storage_bytes test {
|
|
diagnostic_store := diagnostics.init(mem.c_allocator)
|
|
defer diagnostics.deinit(&diagnostic_store)
|
|
modules [2]mut ir.Module := undefined
|
|
{
|
|
session := init(mem.c_allocator)
|
|
defer deinit(&session)
|
|
root :: try add_package(&session)
|
|
dependency :: try add_package(&session)
|
|
bytes := try owned_text(
|
|
`lib :: import "../library"
|
|
`main proc() u64 {
|
|
` value := $(lib.make())
|
|
` saved :: value
|
|
` value.small = 0
|
|
` value.words[1] = 99
|
|
` if (saved.small != 9 or saved.bytes[1] != 255 or saved.bytes[7] != 255) return 0
|
|
` if (saved.bytes[17] != 255 or saved.bytes[23] != 255) return 0
|
|
` generated lib.Generated() :: {}
|
|
` if (generated.value.words[1] != 40 or generated.value.small != 9) return 0
|
|
` return saved.words[1] + saved.words[3]
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&bytes)
|
|
root_source :: try add_source(&session, root, "/union_bytes/app/main.hon", &bytes, &diagnostic_store)
|
|
imported := try owned_text(
|
|
`Pair :: struct { small u8, large u64 }
|
|
`Storage :: union { small u8, rows [2]Pair, words [4]mut u64, bytes [32]u8 }
|
|
`make proc() Storage {
|
|
` value := Storage { words = [maxval!(u64), 40, maxval!(u64), 2] }
|
|
` value.small = 9
|
|
` return value
|
|
`}
|
|
`Generated proc() type {
|
|
` return struct_type!(.auto, ["value"], [Storage], [make()])
|
|
`}
|
|
,
|
|
)
|
|
defer arraylist.deinit(&imported)
|
|
_ = try add_source(&session, dependency, "/union_bytes/library/storage.hon", &imported, &diagnostic_store)
|
|
try arraylist.append(&session.imports, Import{
|
|
node = declaration(&session, root_source, 0).node,
|
|
target = dependency,
|
|
})
|
|
modules[0] = try compile(&session, root, &diagnostic_store)
|
|
errdefer ir.deinit(&modules[0])
|
|
modules[1] = try compile(&session, root, &diagnostic_store)
|
|
}
|
|
defer ir.deinit(&modules[0])
|
|
defer ir.deinit(&modules[1])
|
|
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
|
|
for modules |module| {
|
|
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
|
|
defer interpreter.deinit(&outcome)
|
|
try testing.expect(outcome.trap == null)
|
|
try testing.expect_equal(i64(42), outcome.value.data.integer)
|
|
}
|
|
}
|