feat: run existing ArrayList with imported C allocator

This commit is contained in:
2026-10-29 19:31:54 +01:00
parent 026fe36325
commit 73684f856a
20 changed files with 875 additions and 54 deletions
+21 -1
View File
@@ -133,6 +133,7 @@ lower_module proc(
id :: ast.package_decl(tree, i)
match ast.decl_kind(tree, id) {
.function: {
if (ast.function_external(tree, id) and typecheck.type_of(checked, id).kind == .none) continue
function :: try add_function(&module, ast.node_span(tree, id))
storage[usize(id)] = Storage{ kind = .function, index = u32(function) }
}
@@ -157,7 +158,9 @@ lower_module proc(
for (0..ast.package_decl_count(tree)) |i| {
id :: ast.package_decl(tree, i)
match ast.decl_kind(tree, id) {
.function: try lower_function(&state, id)
.function: {
if (storage[usize(id)].kind == .function) try lower_function(&state, id)
}
.statement: {
if (ast.expr_kind(tree, ast.statement_decl(tree, id).initializer) == .alias_expr) continue
if (typecheck.type_of(checked, id).kind != .type_value) try lower_global(&state, id)
@@ -1735,6 +1738,23 @@ lower_builtin proc(state @mut State, id ast.NodeId) ir.ValueId ! (mem.AllocError
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, "maxval") or mem.eql(name, "minval")) {
type :: lower_type(state, typecheck.type_of(state.checked, id))
value := ir.Value{ type = type }
if (mem.eql(name, "maxval")) value.data = ir.ValueData{ unsigned = ir.integer_max(type) }
else value.data = ir.ValueData{ integer = ir.integer_min(type) }
return try constant(state, value, span)
}
if (mem.eql(name, "divtrunc")) {
left :: try lower_expression(state, ast.call_arg(tree, id, 0))
if (state.terminated) return ir.no_value
right :: try lower_expression(state, ast.call_arg(tree, id, 1))
if (state.terminated) return ir.no_value
return try emit(state, ir.Instruction{
op = .divide, type = lower_type(state, typecheck.type_of(state.checked, id)),
left = left, right = right, span = 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)
+73
View File
@@ -2014,3 +2014,76 @@ fallible_source_handlers_do_not_catch_runtime_allocation_failures test {
}
try testing.expect(succeeded and failures > 0)
}
keeps_generated_foreign_declarations_demand_driven_and_traps_interpreted_calls test {
source ::
`Handle :: opaque
`Packet :: c_struct { context ?*mut Handle, callback ?*c_func(_ c_int, _ c_int) void }
`unsupported c_func(_ Packet) Packet
`variadic c_func(_ c_int, ...) c_int
`single c_func(_ c_float) c_float
`extended c_func(_ c_longdouble) c_longdouble
`double c_func(_ c_double) c_double
`malloc c_func(_ c_ulong) ?*mut anyopaque
`@hide:file
`helper proc() int { if (true) return 42
`else return 0 }
`main proc() int { return helper() }
diagnostic_store := diagnostics.init(mem.c_allocator)
defer diagnostics.deinit(&diagnostic_store)
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(i64(42), outcome.value.data.integer)
foreign_module := try compile_owned(
"realloc c_func(_ ?*mut anyopaque, _ c_ulong) ?*mut anyopaque\nmain proc() bool { return realloc(null, 8) == null }\n",
&diagnostic_store,
)
defer ir.deinit(&foreign_module)
foreign_outcome := try interpreter.run(mem.c_allocator, &foreign_module, &diagnostic_store)
defer interpreter.deinit(&foreign_outcome)
try expect_trap(foreign_outcome, &diagnostic_store, .unsupported_foreign_call)
}
diagnoses_demanded_unsupported_foreign_signatures_and_attributes test {
sources [5][]u8 :: [
"take c_func(_ c_int, ...) c_int\nmain proc() c_int { return take(1) }\n",
"Handle :: opaque\ntake c_func(_ Handle) void\nmain proc() void { take(undefined) }\n",
"A :: opaque\nB :: opaque\nmain proc() void { a ?*A :: null\n b ?*B :: a }\n",
"@other:file\nhidden :: 1\nmain proc() int { return hidden }\n",
"@hide:package\nhidden :: 1\nmain proc() int { return hidden }\n",
]
for sources |source| {
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)
try testing.expect(outcome.trap != null)
}
}
rejects_demanded_unavailable_c_floating_types_without_unknown_names test {
sources [2][]u8 :: [
"single c_func() c_float\nmain proc() void { single() }\n",
"extended c_func() c_longdouble\nmain proc() void { extended() }\n",
]
for sources |source| {
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)
try expect_trap(outcome, &diagnostic_store, .invalid_operand)
for 0..diagnostics.count(&diagnostic_store) |index| {
diagnostic :: diagnostics.get(&diagnostic_store, diagnostics.DiagnosticId(index))?
try testing.expect(diagnostic.code != .unknown_name)
}
}
}