close some gaps in the type system

This commit is contained in:
2026-07-19 01:01:11 +02:00
parent c7e3162ecb
commit 95f90cc306
12 changed files with 367 additions and 78 deletions
+39 -3
View File
@@ -379,6 +379,13 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
case .Keyword_Bool:
advance(parser)
return types.BOOL
case .Left_Paren:
advance(parser)
grouped := parse_type(parser)
if _, ok := allow(parser, .Right_Paren); !ok {
source.add(parser.diagnostics, current(parser).span, "expected ')' after grouped type")
}
return grouped
case .Keyword_Func, .Keyword_C_Func:
c_abi := tok.kind == .Keyword_C_Func
advance(parser)
@@ -447,6 +454,24 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
return types.INVALID
}
sum_syntax_requires_resolution :: proc(parser: ^Parser, value: types.Type, depth := 0) -> bool {
if depth > 64 {
return true
}
item, ok := types.node(&parser.module.type_store, value)
if !ok {
return false
}
if item.kind == .Named || item.kind == .Type_Call {
return true
}
if item.kind == .Alias || item.kind == .Sum {
return sum_syntax_requires_resolution(parser, item.child, depth+1) ||
sum_syntax_requires_resolution(parser, item.extra, depth+1)
}
return false
}
parse_type_pipe_tail :: proc(parser: ^Parser, left: ast.Type_Syntax) -> ast.Type_Syntax {
result := left
for current(parser).kind == .Pipe {
@@ -454,8 +479,12 @@ parse_type_pipe_tail :: proc(parser: ^Parser, left: ast.Type_Syntax) -> ast.Type
right := parse_type_atom(parser)
composed, compose_error := types.compose_sum(&parser.module.type_store, result, right)
if compose_error == .Unsupported {
source.add(parser.diagnostics, operator.span, "only native unbacked enums and tagged unions can be composed with '|'")
result = types.INVALID
if sum_syntax_requires_resolution(parser, result) || sum_syntax_requires_resolution(parser, right) {
result = types.sum_syntax(&parser.module.type_store, result, right)
} else {
source.add(parser.diagnostics, operator.span, "only native unbacked enums and tagged unions can be composed with '|'")
result = types.INVALID
}
} else if compose_error == .Conflict {
source.add(parser.diagnostics, operator.span, "sum composition contains the same variant name with different payload types")
result = types.INVALID
@@ -738,9 +767,15 @@ parse_anonymous_struct_type_expr :: proc(parser: ^Parser) -> ast.Expr_Id {
start := advance(parser)
fields: [dynamic]types.Field
fields.allocator = parser.module.allocator
defaults: [dynamic]ast.Expr_Id
defaults.allocator = parser.module.allocator
tuple := false
if !parse_record_body(parser, &fields, "expected '{' after anonymous struct type", tuple_result=&tuple) {
if !parse_record_body(
parser, &fields, "expected '{' after anonymous struct type",
tuple_result=&tuple, defaults=&defaults,
) {
delete(fields)
delete(defaults)
return invalid_expr(parser, start.span, "invalid anonymous struct type")
}
end := previous(parser)
@@ -752,6 +787,7 @@ parse_anonymous_struct_type_expr :: proc(parser: ^Parser) -> ast.Expr_Id {
kind=.Anonymous_Struct_Type,
span=span_from(start.span, end.span),
integer=u64(field_start)<<32 | u64(field_count),
args=defaults[:],
tuple=tuple,
left=ast.INVALID_EXPR,
right=ast.INVALID_EXPR,