feat: materialize address-free compile-time untagged unions

Snapshot full union storage rather than choosing an overlapping field. Preserve structural union source syntax independently of nominal identity so direct literal arguments materialize and share normalized specialization keys. Reject uninitialized bytes and address-bearing member layouts.
This commit is contained in:
2026-10-30 15:54:32 +01:00
parent c8890b4355
commit cc39c96fc0
9 changed files with 420 additions and 25 deletions
+60
View File
@@ -1006,3 +1006,63 @@ computed_byte_slices_recompile_without_borrowing_evaluation_storage test {
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)
}
}