finite-domain enum return analysis

This commit is contained in:
2026-07-20 15:12:20 +02:00
parent 10abba54a5
commit deab47e75e
2 changed files with 134 additions and 6 deletions
+52
View File
@@ -9519,6 +9519,42 @@ main func() void {
testing.expect(t, !found)
}
@(test)
exhaustive_enum_guard_sequences_return :: proc(t: ^testing.T) {
text := `E :: enum { a, b }
complete func(value E) i32 {
if (value == .a) { return 1 }
if (value == .b) { return 2 }
}
incomplete func(value E) i32 {
if (value == .a) { return 1 }
}
main func() void {
_ = complete(.a)
_ = incomplete(.a)
}
`
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)
missing_returns := 0
for diagnostic in diagnostics.items {
if strings.contains(diagnostic.message, "does not return a value") {
missing_returns += 1
}
}
testing.expect_value(t, missing_returns, 1)
}
@(test)
conditional_unwrap_compiles_and_runs :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-conditional-unwrap"
@@ -13844,6 +13880,18 @@ init func($E, $V type, values meta.EnumFieldStruct(E, ?V, some!(none))) Map(E, V
return map
}
get func($E, $V type, map @Map(E, V), key E) ?V {
match typeinfo!(E) {
.enum |info|: expand for info.fields |field, index| {
if key == field!(E, field.name) {
if map.present[index] { return map.values[index] }
return none
}
}
else: compile_error!("EnumMap key must be an enum")
}
}
main func() i32 {
_ = ordered
inferred :: {x = 40, name = "bro"}
@@ -13889,6 +13937,10 @@ main func() i32 {
})
if !map.present[0] or !map.present[1] or map.present[2] { return 9 }
if map.values[0].len != 10 or map.values[1].len != 7 { return 18 }
if get(TokenKind, []u8, &map, TokenKind.ident) |value| {
if value.len != 10 { return 19 }
} else { return 20 }
if get(TokenKind, []u8, &map, TokenKind.eof) |_| { return 21 }
return 0
}
`