comptime storage and function values

This commit is contained in:
2026-07-03 23:23:36 +02:00
parent ee41a54e41
commit 4ebe9c90e9
8 changed files with 1255 additions and 119 deletions
+77 -7
View File
@@ -293,6 +293,43 @@ main func() void {}
testing.expect(t, params[0].type == types.C_INT)
}
@(test)
parser_accepts_native_function_pointer_types :: proc(t: ^testing.T) {
text := `Error :: enum {
bad
}
take func(callback ?*func(value i32) i32, fallible *func() i32 ! Error) void
main func() void {}
`
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)
module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&module)
optional, optional_ok := types.node(&module.type_store, module.functions[0].params[0].type)
pointer, pointer_ok := types.node(&module.type_store, optional.child)
function, function_ok := types.node(&module.type_store, pointer.child)
params := types.params_for(&module.type_store, pointer.child)
fallible_pointer, fallible_pointer_ok := types.node(&module.type_store, module.functions[0].params[1].type)
fallible_function, fallible_function_ok := types.node(&module.type_store, fallible_pointer.child)
fallible, fallible_ok := types.node(&module.type_store, fallible_function.child)
testing.expect_value(t, len(diagnostics.items), 0)
testing.expect(t, optional_ok && optional.kind == .Optional)
testing.expect(t, pointer_ok && pointer.kind == .Pointer && pointer.many && !pointer.mutable)
testing.expect(t, function_ok && function.kind == .Function && !function.c_abi && !function.variadic)
testing.expect(t, function.child == types.I32)
testing.expect_value(t, len(params), 1)
testing.expect(t, params[0].type == types.I32)
testing.expect(t, fallible_pointer_ok && fallible_pointer.kind == .Pointer)
testing.expect(t, fallible_function_ok && fallible_function.kind == .Function && !fallible_function.c_abi)
testing.expect(t, fallible_ok && fallible.kind == .Fallible && fallible.child == types.I32)
}
@(test)
parser_accepts_c_function_pointer_alias_types :: proc(t: ^testing.T) {
text := `callback_alias :: alias ?*c_func(value i32) i32
@@ -882,13 +919,15 @@ main func() void {
defer hir.destroy_module(&hir_module)
found_global := false
found_function := false
found_old_function_error := false
for diagnostic in diagnostics.items {
found_global = found_global || strings.contains(diagnostic.message, "'value' is a global, not a function")
found_function = found_function || strings.contains(diagnostic.message, "'give' is a function, not a global value")
found_old_function_error =
found_old_function_error ||
strings.contains(diagnostic.message, "'give' is a function, not a global value")
}
testing.expect(t, found_global)
testing.expect(t, found_function)
testing.expect(t, !found_old_function_error)
}
@(test)
@@ -2354,6 +2393,10 @@ main func() void {
runtime i32 = 1
_ = $runtime
_ = $native()
_ = ${
callback :: native
yield callback()
}
_ = $&GLOBAL
_ = $spin()
_ = $missing()
@@ -2375,7 +2418,7 @@ main func() void {
defer hir.destroy_module(&hir_module)
found_runtime := false
found_external := false
runtime_only_count := 0
found_pointer := false
found_quota := false
found_missing := false
@@ -2383,20 +2426,47 @@ main func() void {
for diagnostic in diagnostics.items {
message := diagnostic.message
found_runtime = found_runtime || strings.contains(message, "unresolved comptime value 'runtime'")
found_external = found_external || strings.contains(message, "runtime-only")
found_pointer = found_pointer || strings.contains(message, "pointers and slices are not supported")
runtime_only_count += 1 if strings.contains(message, "runtime-only") else 0
found_pointer = found_pointer || strings.contains(message, "comptime storage pointers and slices cannot materialize as runtime memory")
found_quota = found_quota || strings.contains(message, "comptime evaluation exceeded the step quota")
found_missing = found_missing || strings.contains(message, "did not return a value")
found_yield = found_yield || strings.contains(message, "comptime block must yield a value")
}
testing.expect(t, found_runtime)
testing.expect(t, found_external)
testing.expect(t, runtime_only_count >= 2)
testing.expect(t, found_pointer)
testing.expect(t, found_quota)
testing.expect(t, found_missing)
testing.expect(t, found_yield)
}
@(test)
native_function_pointer_type_restrictions_are_diagnosed :: proc(t: ^testing.T) {
text := `main func() void {
callback *func(...) void = undefined
}
`
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)
found_variadic := false
for diagnostic in diagnostics.items {
found_variadic =
found_variadic ||
strings.contains(diagnostic.message, "native function pointer types do not support variadic parameters")
}
testing.expect(t, found_variadic)
}
@(test)
unused_function_signatures_are_validated_eagerly :: proc(t: ^testing.T) {
text := `broken func(value, value i8, nope void) void {}