fix: allow multiline grouped sum types
This commit is contained in:
+1
-1
@@ -44,7 +44,7 @@ roadmap and milestone history.
|
||||
- compiler-reordered native structs with fields laid out by decreasing alignment (declaration order breaks ties and remains the reflection/diagnostic order), opaque nominal records with `Name :: opaque`, complete source-order `c_struct { ... }`, keyed record literals, native untagged unions, and native tagged unions `union(Enum)` / `union(enum)`
|
||||
- named native struct fields may declare defaults with `field T = expression`; keyed literals use defaults for omitted fields and explicit initializers override them
|
||||
- void-payload tagged-union variants, anonymous struct payloads, contextual `.variant`, `.variant{payload}`, and `.variant{field = value}` construction
|
||||
- native sum composition with `A | B` for unbacked enums and tagged unions, optionally grouped as `(A | B)`, using program-global `u16` variant ids
|
||||
- native sum composition with `A | B` for unbacked enums and tagged unions, optionally grouped as `(A | B)`, using program-global `u16` variant ids; parenthesized types allow newlines after `(`, before `)`, and on either side of `|`, including in aliases and fallible signatures
|
||||
- fallible channel types `T ! E`, where `E` is a native enum, native struct, tagged union, or supported sum composition; `void ! E` functions complete successfully on fallthrough, and void-success `catch` handlers may fall through without `yield`
|
||||
- bodyful local functions and root `main` may write `T!` to infer a specialization-local error channel from propagated `try` expressions and concretely typed error returns; inference composes only existing named error types, never synthesizes variants, and requires at least one inferred error
|
||||
|
||||
|
||||
@@ -429,7 +429,8 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
|
||||
return types.BOOL
|
||||
case .Left_Paren:
|
||||
advance(parser)
|
||||
grouped := parse_type(parser)
|
||||
skip_newlines(parser)
|
||||
grouped := parse_type_pipe_tail(parser, parse_type_atom(parser), true)
|
||||
if _, ok := allow(parser, .Right_Paren); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ')' after grouped type")
|
||||
}
|
||||
@@ -533,10 +534,19 @@ sum_syntax_requires_resolution :: proc(parser: ^Parser, value: types.Type, depth
|
||||
return false
|
||||
}
|
||||
|
||||
parse_type_pipe_tail :: proc(parser: ^Parser, left: ast.Type_Syntax) -> ast.Type_Syntax {
|
||||
parse_type_pipe_tail :: proc(parser: ^Parser, left: ast.Type_Syntax, multiline := false) -> ast.Type_Syntax {
|
||||
result := left
|
||||
for current(parser).kind == .Pipe {
|
||||
for {
|
||||
if multiline {
|
||||
skip_newlines(parser)
|
||||
}
|
||||
if current(parser).kind != .Pipe {
|
||||
break
|
||||
}
|
||||
operator := advance(parser)
|
||||
if multiline {
|
||||
skip_newlines(parser)
|
||||
}
|
||||
right := parse_type_atom(parser)
|
||||
composed, compose_error := types.compose_sum(&parser.module.type_store, result, right)
|
||||
if compose_error == .Unsupported {
|
||||
|
||||
@@ -7680,6 +7680,65 @@ main func() i32 {
|
||||
testing.expect(t, strings.contains(llvm_text, "call void @llvm.memcpy.p0.p0.i64"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
multiline_grouped_sum_types_compile_and_run :: proc(t: ^testing.T) {
|
||||
directory :: "/tmp/brolang-test-multiline-sums"
|
||||
output := "/tmp/brolang-test-multiline-sums-output"
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.make_directory(directory + "/errors") == nil)
|
||||
errors_text := `AllocError :: enum { alloc }
|
||||
CapacityError :: enum { capacity }
|
||||
SourceError :: union(enum) { source i32 }
|
||||
`
|
||||
testing.expect(t, os.write_entire_file(directory + "/errors/errors.hon", transmute([]byte)errors_text))
|
||||
text := `errors :: import "errors"
|
||||
@hide:file
|
||||
DriverError :: alias (
|
||||
errors.AllocError
|
||||
| (
|
||||
errors.CapacityError |
|
||||
errors.SourceError
|
||||
)
|
||||
)
|
||||
code func(err DriverError) i32 {
|
||||
return match err {
|
||||
.alloc: 1
|
||||
.capacity: 2
|
||||
.source |value|: value
|
||||
}
|
||||
}
|
||||
fail func() void ! (
|
||||
errors.AllocError
|
||||
|
|
||||
errors.CapacityError
|
||||
) {
|
||||
return .capacity
|
||||
}
|
||||
main func() i32 {
|
||||
if (code(.alloc) != 1) return 1
|
||||
if (code(.capacity) != 2) return 2
|
||||
if (code(.source{42}) != 42) return 3
|
||||
result := 0
|
||||
fail() catch |err| {
|
||||
result = code(err)
|
||||
}
|
||||
if (result != 2) return 4
|
||||
return 0
|
||||
}
|
||||
`
|
||||
testing.expect(t, os.write_entire_file(directory + "/main.hon", transmute([]byte)text))
|
||||
status := compiler_core.compile_package(directory, output)
|
||||
testing.expect_value(t, status, 0)
|
||||
if status != 0 {
|
||||
return
|
||||
}
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
anonymous_struct_payloads_and_keyed_payload_sugar_compile :: proc(t: ^testing.T) {
|
||||
text := `PayloadError :: union(enum) {
|
||||
|
||||
Reference in New Issue
Block a user