contextual void construction
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user