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)`
|
- 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
|
- 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
|
- 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`
|
- 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
|
- 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
|
return types.BOOL
|
||||||
case .Left_Paren:
|
case .Left_Paren:
|
||||||
advance(parser)
|
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 {
|
if _, ok := allow(parser, .Right_Paren); !ok {
|
||||||
source.add(parser.diagnostics, current(parser).span, "expected ')' after grouped type")
|
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
|
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
|
result := left
|
||||||
for current(parser).kind == .Pipe {
|
for {
|
||||||
|
if multiline {
|
||||||
|
skip_newlines(parser)
|
||||||
|
}
|
||||||
|
if current(parser).kind != .Pipe {
|
||||||
|
break
|
||||||
|
}
|
||||||
operator := advance(parser)
|
operator := advance(parser)
|
||||||
|
if multiline {
|
||||||
|
skip_newlines(parser)
|
||||||
|
}
|
||||||
right := parse_type_atom(parser)
|
right := parse_type_atom(parser)
|
||||||
composed, compose_error := types.compose_sum(&parser.module.type_store, result, right)
|
composed, compose_error := types.compose_sum(&parser.module.type_store, result, right)
|
||||||
if compose_error == .Unsupported {
|
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"))
|
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)
|
@(test)
|
||||||
anonymous_struct_payloads_and_keyed_payload_sugar_compile :: proc(t: ^testing.T) {
|
anonymous_struct_payloads_and_keyed_payload_sugar_compile :: proc(t: ^testing.T) {
|
||||||
text := `PayloadError :: union(enum) {
|
text := `PayloadError :: union(enum) {
|
||||||
|
|||||||
Reference in New Issue
Block a user