typed alloc

This commit is contained in:
2026-07-12 00:29:22 +02:00
parent 220b1c6e82
commit fbbbfa454c
6 changed files with 328 additions and 66 deletions
+91 -4
View File
@@ -1413,6 +1413,83 @@ main func() i32 {
testing.expect_value(t, state.exit_code, 0)
}
@(test)
integer_bound_builtins_compile_and_run :: proc(t: ^testing.T) {
directory := "/tmp/brolang-test-integer-bounds"
main_path := "/tmp/brolang-test-integer-bounds/main.bro"
output := "/tmp/brolang-test-integer-bounds-output"
text := `MAX_U64 u64 :: max_value(u64)
maximum func($T type) T {
return max_value(T)
}
main func() i32 {
if (min_value(i8) != -128) return 1
if (max_value(i8) != 127) return 2
if (min_value(u8) != 0) return 3
if (max_value(u8) != 255) return 4
if (min_value(isize) != -9223372036854775808) return 5
if (max_value(usize) != 18446744073709551615) return 6
if (MAX_U64 != 18446744073709551615) return 7
if (maximum(u16) != 65535) return 8
if (min_value(c_int) != -2147483648) return 9
if (max_value(c_ulong) != 18446744073709551615) return 10
return 0
}
`
_ = os2.remove_all(directory)
defer _ = os2.remove_all(directory)
defer _ = os.remove(output)
testing.expect(t, os.make_directory(directory) == nil)
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
status := compiler_core.compile_package(directory, output)
testing.expect_value(t, status, 0)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 0)
}
@(test)
integer_bound_builtins_reject_invalid_targets :: proc(t: ^testing.T) {
text := `Named :: distinct u8
Choice :: enum { one }
main func() void {
_ = min_value()
_ = max_value(u8, u16)
_ = min_value(1)
_ = max_value(int)
_ = max_value(f32)
_ = max_value(bool)
_ = max_value(Named)
_ = max_value(Choice)
}
`
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
ast_module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&ast_module)
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
defer hir.destroy_module(&hir_module)
bad_arity := 0
bad_type := false
bad_target := 0
for diagnostic in diagnostics.items {
bad_arity += 1 if strings.contains(diagnostic.message, "expects 1 argument") else 0
bad_type = bad_type || strings.contains(diagnostic.message, "integer bound target must be a type")
bad_target += 1 if strings.contains(diagnostic.message, "integer bound target must be a concrete integer type") else 0
}
testing.expect_value(t, bad_arity, 2)
testing.expect(t, bad_type)
testing.expect_value(t, bad_target, 5)
}
@(test)
layout_builtins_reject_unsized_targets :: proc(t: ^testing.T) {
text := `Opaque :: opaque
@@ -3281,6 +3358,7 @@ allocator_contract_c_allocator_global_lowers :: proc(t: ^testing.T) {
found_c_allocator := false
found_anyopaque_context := false
found_vtable_pointer := false
found_alloc_callback := false
found_realloc_callback := false
found_free_callback := false
@@ -3291,7 +3369,6 @@ allocator_contract_c_allocator_global_lowers :: proc(t: ^testing.T) {
found_c_allocator = true
for field in types.fields_for(&hir_module.types, global.type) {
name := symbol.resolve(&symbols, symbol.Id(field.name))
callback_pointer, _, _, callable := types.function_pointer(field.type, &hir_module.types)
if name == "context" {
optional_item, optional_ok := types.node(&hir_module.types, field.type)
if optional_ok && optional_item.kind == .Optional {
@@ -3302,10 +3379,19 @@ allocator_contract_c_allocator_global_lowers :: proc(t: ^testing.T) {
pointer_item.many &&
pointer_item.child == types.ANYOPAQUE
}
} else if name == "vtable" {
pointer_item, pointer_ok := types.node(&hir_module.types, field.type)
found_vtable_pointer = pointer_ok && pointer_item.kind == .Pointer && !pointer_item.mutable && !pointer_item.many
if found_vtable_pointer {
for callback in types.fields_for(&hir_module.types, pointer_item.child) {
callback_name := symbol.resolve(&symbols, symbol.Id(callback.name))
callback_pointer, _, _, callable := types.function_pointer(callback.type, &hir_module.types)
found_alloc_callback = found_alloc_callback || callback_name == "alloc" && callable && !callback_pointer.many
found_realloc_callback = found_realloc_callback || callback_name == "realloc" && callable && !callback_pointer.many
found_free_callback = found_free_callback || callback_name == "free" && callable && !callback_pointer.many
}
}
}
found_alloc_callback = found_alloc_callback || name == "alloc" && callable && !callback_pointer.many
found_realloc_callback = found_realloc_callback || name == "realloc" && callable && !callback_pointer.many
found_free_callback = found_free_callback || name == "free" && callable && !callback_pointer.many
}
}
@@ -3313,6 +3399,7 @@ allocator_contract_c_allocator_global_lowers :: proc(t: ^testing.T) {
testing.expect(t, len(ir_module.functions) > 0)
testing.expect(t, found_c_allocator)
testing.expect(t, found_anyopaque_context)
testing.expect(t, found_vtable_pointer)
testing.expect(t, found_alloc_callback)
testing.expect(t, found_realloc_callback)
testing.expect(t, found_free_callback)