feat: support existing enum map initialization and lookup

This commit is contained in:
2026-10-29 16:09:16 +01:00
parent 6f892bbfcc
commit 026fe36325
12 changed files with 409 additions and 27 deletions
+18 -2
View File
@@ -1725,8 +1725,16 @@ lower_slice proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError |
lower_builtin proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError | diagnostics.CapacityError) {
tree :: state.tree
span :: ast.node_span(tree, id)
name :: ast.source_text(tree, ast.node_span(tree, ast.builtin_call(tree, id).name))
name :: ast.literal_text(tree, ast.builtin_call(tree, id).name)
if (trap_type(state, id)) return ir.no_value
if (mem.eql(name, "some")) {
type :: typecheck.type_of(state.checked, id)
child :: typecheck.array_type(state.checked, type.array_type).element
payload :: try lower_as(state, ast.call_arg(tree, id, 0), child)
if (state.terminated or child.kind == .pointer or child.kind == .function) return payload
present :: try constant(state, ir.Value{ type = .bool, data = ir.ValueData{ boolean = true } }, span)
return try record_pair(state, try array_shape(state, type), present, payload, span)
}
if (mem.eql(name, "sizeof") or mem.eql(name, "alignof")) {
checked :: typecheck.type_of(state.checked, ast.call_arg(tree, id, 0))
type :: lower_type(state, checked)
@@ -1893,7 +1901,15 @@ lower_expression proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocEr
if (!trap_type(state, id)) trap(state, try diagnostics.add(state.diagnostics, .type_not_value, span), span)
}
.alias_expr: return try lower_expression(state, ast.type_operand(tree, id))
.enum_literal, .literal_undefined: {
.literal_undefined: {
if (trap_type(state, id)) return ir.no_value
checked :: typecheck.type_of(state.checked, id)
return try emit(state, ir.Instruction{
op = .undefined_value, type = lower_type(state, checked),
array_type = try array_shape(state, checked), span = span,
})
}
.enum_literal: {
if (!trap_type(state, id)) unreachable
}
.match_expr: return try lower_match(state, id)
+60
View File
@@ -174,6 +174,66 @@ supports_bare_void_value_returns_and_fallthrough test {
}
}
constructs_present_optionals_without_losing_nested_null_or_repeating_values test {
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
source ::
`next proc(calls @mut i16) i16 {
` calls^ = calls^ + 1
` return 42
`}
`nested proc() ??i16 { return some!(null) }
`Box :: struct { values [2]i16 }
`main proc() bool {
` calls i16 := 0
` absent ??i16 :: null
` present ??i16 :: nested()
` full ??i16 :: some!(some!(42))
` exact i16 :: 42
` value ?i16 :: some!(exact)
` once ?i16 :: some!(next(&calls))
` boxed ?Box :: some!(Box{ values = [20, 22] })
` pointer ?@i16 :: some!(&exact)
` nested_pointer ??@i16 :: some!(null)
` return (
` absent == null and present != null and present? == null
` and full != null and full? != null and full?? == 42
` and value? == 42 and once? == 42 and calls == 1
` and boxed?.values[0] + boxed?.values[1] == 42
` and pointer?^ == 42 and nested_pointer != null and nested_pointer? == null
` )
`}
module := try compile_owned(source, &diagnostic_store)
defer ir.deinit(&module)
try testing.expect_equal(0, diagnostics.count(&diagnostic_store))
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
defer interpreter.deinit(&outcome)
try testing.expect(outcome.trap == null)
try testing.expect_equal(ir.Type.bool, outcome.value.type)
try testing.expect(outcome.value.data.boolean)
}
rejects_some_without_optional_context_wrong_arity_and_inexact_payloads test {
sources [6][]u8 :: [
"main proc() ?i16 { return some!() }\n",
"main proc() ?i16 { return some!(1, 2) }\n",
"main proc() bool { return some!(true) }\n",
"main proc() ?i16 { return some!(true) }\n",
"main proc() ?i16 { value i32 :: 42\nreturn some!(value) }\n",
"main proc() ?i16 { return some!(null) }\n",
]
for (sources) |source, i| {
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
module := try compile_owned(source, &diagnostic_store)
defer ir.deinit(&module)
outcome := try interpreter.run(mem.c_allocator, &module, &diagnostic_store)
defer interpreter.deinit(&outcome)
code diagnostics.Code :: if (i < 2) .argument_count_mismatch else if (i == 2) .invalid_operand else .type_mismatch
try expect_trap(outcome, &diagnostic_store, code)
}
}
preserves_demanded_diagnostic_identity_and_source_location test {
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)