upgrade enum discriminants

This commit is contained in:
2026-07-17 20:32:12 +02:00
parent 866e28adb8
commit cedc63b28b
19 changed files with 3168 additions and 96 deletions
+35 -6
View File
@@ -2783,6 +2783,8 @@ parse_enum_body :: proc(
explicit_backing: bool,
backing: ^types.Type,
members: ^[dynamic]types.Enum_Member,
values: ^[dynamic]ast.Enum_Value,
deferred: ^bool,
expected_open: string,
) -> bool {
skip_newlines(parser)
@@ -2793,6 +2795,7 @@ parse_enum_body :: proc(
next_value: i128
previous_value: i128
has_previous := false
order_known := true
skip_newlines(parser)
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
member, member_ok := parse_member_name(parser)
@@ -2817,18 +2820,20 @@ parse_enum_body :: proc(
source.addf(parser.diagnostics, member.span, "duplicate enum member '%s'", token_text(parser, member))
}
value := next_value
explicit := false
value_expr := ast.INVALID_EXPR
if _, ok := allow(parser, .Equal); ok {
explicit = true
if !explicit_backing {
source.add(parser.diagnostics, member.span, "explicit enum values require a backing type")
}
saved := parser.cursor
negative := false
if _, minus_ok := allow(parser, .Minus); minus_ok {
negative = true
}
literal := current(parser)
if literal.kind != .Integer {
source.add(parser.diagnostics, literal.span, "expected a decimal integer literal for enum value")
} else {
if literal.kind == .Integer {
advance(parser)
magnitude, magnitude_ok := parse_integer_magnitude(token_text(parser, literal))
if !magnitude_ok {
@@ -2839,13 +2844,19 @@ parse_enum_body :: proc(
value = -value
}
}
} else {
parser.cursor = saved
value_expr = parse_expression(parser)
deferred^ = true
order_known = false
}
}
if has_previous && value <= previous_value {
if order_known && has_previous && value <= previous_value {
source.add(parser.diagnostics, member.span, "enum values must be strictly increasing")
}
if !duplicate {
append(members, types.Enum_Member{name=u32(member.symbol), value=value})
append(values, ast.Enum_Value{expr=value_expr, span=member.span, explicit=explicit})
}
previous_value = value
has_previous = true
@@ -2890,7 +2901,11 @@ parse_inline_enum_type :: proc(parser: ^Parser) -> types.Type {
members: [dynamic]types.Enum_Member
members.allocator = parser.module.allocator
defer delete(members)
if !parse_enum_body(parser, start.span, false, &backing, &members, "expected '{' after inline enum error type") || !valid {
values: [dynamic]ast.Enum_Value
values.allocator = parser.module.allocator
defer delete(values)
deferred := false
if !parse_enum_body(parser, start.span, false, &backing, &members, &values, &deferred, "expected '{' after inline enum error type") || !valid {
return types.INVALID
}
return types.enum_anonymous(&parser.module.type_store, members[:], backing)
@@ -2910,7 +2925,11 @@ parse_enum :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
members: [dynamic]types.Enum_Member
members.allocator = parser.module.allocator
defer delete(members)
if !parse_enum_body(parser, start.span, explicit_backing, &backing, &members, "expected '{' after enum declaration") {
values: [dynamic]ast.Enum_Value
values.allocator = parser.module.allocator
defer delete(values)
deferred := false
if !parse_enum_body(parser, start.span, explicit_backing, &backing, &members, &values, &deferred, "expected '{' after enum declaration") {
_ = finish_statement(parser)
return
}
@@ -2918,6 +2937,16 @@ parse_enum :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
if !types.define_enum(&parser.module.type_store, id, backing, members[:], explicit_backing) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
if explicit_backing && deferred {
stored := make([]ast.Enum_Value, len(values), parser.module.allocator)
copy(stored, values[:])
append(&parser.module.enum_declarations, ast.Enum_Declaration{
type=id,
pkg=parser.pkg,
file=parser.file,
values=stored,
})
}
_ = finish_statement(parser)
}