contextual void construction

This commit is contained in:
2026-06-29 20:24:48 +02:00
parent c82f070d55
commit 98c303d22c
4 changed files with 185 additions and 8 deletions
+92
View File
@@ -2527,6 +2527,98 @@ main :: func() i32 {
testing.expect(t, found_incompatible)
}
@(test)
match_call_subject_and_contextual_void_compile :: proc(t: ^testing.T) {
// Milestone 22.6: (1) a call expression directly as the match subject (`match get()`)
// now specializes previously "could not resolve specialization of 'get'" because the
// inference pass visits the match subject; (2) a void variant constructed contextually
// (`e Box = .empty`) coerces the bare enum literal to the union. Both compile clean to IR.
text := `Animal :: enum {
dog
cat
bird
}
Box :: union(enum) {
count i32
empty void
}
get :: func() Animal {
return .bird
}
main :: func() i32 {
e Box = .empty
r i32 = 0
match get() {
.dog: r = 1
.cat: r = 2
.bird: r = 3
}
match e {
.count |c|: r = r + c
.empty: r = r + 7
}
return r
}
`
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)
ir_module := lower.lower(&hir_module)
defer ir.destroy_module(&ir_module)
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
defer delete(llvm_text)
testing.expect_value(t, len(diagnostics.items), 0)
testing.expect(t, strings.contains(llvm_text, "icmp eq")) // the call subject still dispatches
}
@(test)
match_contextual_payload_variant_is_diagnosed :: proc(t: ^testing.T) {
// Contextual construction is only for void variants; a bare `.point` for a payload
// variant must use `Box{ point = ... }` instead.
text := `Point :: struct {
x i32
y i32
}
Box :: union(enum) {
point Point
empty void
}
bad :: func() i32 {
e Box = .point
return 0
}
main :: func() i32 {
return bad()
}
`
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, "needs a payload")
}
testing.expect(t, found)
}
@(test)
yield_misuse_is_diagnosed :: proc(t: ^testing.T) {
// A value block that does not end in `yield`, and a `yield` nested inside an