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:
@@ -60,6 +60,8 @@ RecordField :: struct {
|
||||
|
||||
RecordType :: struct {
|
||||
declaration ast.NodeId
|
||||
# union syntax remains available even when structural checking erases nominal identity.
|
||||
source ast.NodeId = ast.NodeId(maxval!(u32))
|
||||
fields []RecordField
|
||||
is_union bool = false
|
||||
tag_type Type = Type{}
|
||||
@@ -1291,6 +1293,14 @@ collect_expression proc(state @mut State, id ast.NodeId) void ! (mem.AllocError
|
||||
try depend(state, value.type, id)
|
||||
try depend(state, value.value, id)
|
||||
}
|
||||
.union_constant: {
|
||||
value :: ast.union_constant(tree, id)
|
||||
state.cells[usize(id)].fixed = true
|
||||
state.cells[usize(id)].type = try check_annotation(state, value.type, false)
|
||||
try collect_expression(state, value.value)
|
||||
try depend(state, value.type, id)
|
||||
try depend(state, value.value, id)
|
||||
}
|
||||
.try_expr: {
|
||||
operand :: ast.type_operand(tree, id)
|
||||
try collect_expression(state, operand)
|
||||
@@ -2156,6 +2166,18 @@ validate proc(state @mut State, id ast.NodeId) void ! (mem.AllocError | diagnost
|
||||
value :: ast.typed_constant(tree, id)
|
||||
try compatible(state, value.value, state.cells[usize(id)].type)
|
||||
}
|
||||
.union_constant: {
|
||||
value :: ast.union_constant(tree, id)
|
||||
type :: state.cells[usize(id)].type
|
||||
if (type.kind == .invalid) return
|
||||
if (type.kind != .record or ast.expr_kind(tree, value.value) != .literal_string) {
|
||||
try fail(state, id, .invalid_operand, ast.node_span(tree, id))
|
||||
return
|
||||
}
|
||||
descriptor :: state.records.items[usize(type.record_type)]
|
||||
if (!descriptor.is_union or descriptor.tag_type.kind != .none)
|
||||
try fail(state, id, .invalid_operand, ast.node_span(tree, id))
|
||||
}
|
||||
.try_expr, .catch_expr: try validate_fallible_expression(state, id)
|
||||
.unary: {
|
||||
expression :: ast.unary_expr(tree, id)
|
||||
@@ -4195,7 +4217,7 @@ check_union proc(state @mut State, id ast.NodeId, nominal bool) Type ! (mem.Allo
|
||||
empty :: try mem.alloc(RecordField, state.records.allocator, 0)
|
||||
declaration :: if (nominal) id else ast.NodeId(maxval!(u32))
|
||||
arraylist.append(&state.records, RecordType{
|
||||
declaration = declaration, fields = empty, is_union = true,
|
||||
declaration = declaration, source = id, fields = empty, is_union = true,
|
||||
}) catch |err| {
|
||||
mem.free(state.records.allocator, empty)
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user