function literals (non-capturing)

This commit is contained in:
2026-07-07 17:04:38 +02:00
parent 95c61311ca
commit f171a6579d
5 changed files with 186 additions and 20 deletions
+46 -5
View File
@@ -2913,19 +2913,21 @@ milestone_24_rejects_invalid_forms :: proc(t: ^testing.T) {
}
@(test)
field_function_pointer_calls_lower_as_indirect_calls :: proc(t: ^testing.T) {
function_literals_lower_as_function_pointer_values :: proc(t: ^testing.T) {
text := `Callbacks :: struct {
call @func(value i32) i32
value i32
}
plus_one func(value i32) i32 {
return value + 1
}
run func(callbacks Callbacks) i32 {
return callbacks.call(callbacks.value)
}
main func() i32 {
callbacks Callbacks = Callbacks { call = plus_one, value = 41 }
callbacks Callbacks = Callbacks {
call = func(value i32) i32 {
return value + 1
},
value = 41,
}
return run(callbacks) - 42
}
`
@@ -2943,6 +2945,14 @@ main func() i32 {
ir_module := lower.lower(&hir_module)
defer ir.destroy_module(&ir_module)
generated_functions := 0
literal_exprs := 0
for function in ast_module.functions {
generated_functions += 1 if function.generated else 0
}
for expr in ast_module.exprs {
literal_exprs += 1 if expr.kind == .Function_Literal else 0
}
indirect_calls := 0
for expr in hir_module.exprs {
if expr.kind == .Call && expr.left != hir.INVALID_EXPR {
@@ -2950,10 +2960,41 @@ main func() i32 {
}
}
testing.expect_value(t, len(diagnostics.items), 0)
testing.expect_value(t, generated_functions, 1)
testing.expect_value(t, literal_exprs, 1)
testing.expect(t, len(ir_module.functions) > 0)
testing.expect(t, indirect_calls > 0)
}
@(test)
function_literals_do_not_capture_locals :: proc(t: ^testing.T) {
text := `main func() i32 {
offset i32 = 1
callback @func(value i32) i32 = func(value i32) i32 {
return value + offset
}
return callback(1)
}
`
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 := false
for diagnostic in diagnostics.items {
found = found || strings.contains(diagnostic.message, "unresolved global 'offset'")
}
testing.expect(t, found)
}
@(test)
field_function_pointer_calls_reject_non_callable_fields :: proc(t: ^testing.T) {
text := `Box :: struct {