contextual payload construction

This commit is contained in:
2026-06-30 21:14:59 +02:00
parent 7ca7e33033
commit 5161e99af5
5 changed files with 450 additions and 85 deletions
+31 -12
View File
@@ -758,7 +758,7 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
if expr.left != ast.INVALID_EXPR {
append(&stack, expr.left)
}
case .Negate, .Not, .Address, .Deref, .Field, .Unwrap, .Try, .Keyed:
case .Negate, .Not, .Address, .Deref, .Field, .Unwrap, .Try, .Keyed, .Enum_Literal:
append(&stack, expr.left)
case .Catch:
append(&stack, expr.left)
@@ -768,7 +768,7 @@ mark_expr_imports_used :: proc(checker: ^Checker, expr_id: ast.Expr_Id, file: as
mark_block_imports_used(checker, expr.body, file)
case .Add, .Sub, .Mul, .Div, .Index, .Orelse, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or, .Range:
append(&stack, expr.left, expr.right)
case .Invalid, .Integer, .Float, .String, .Bool, .None, .Undefined, .Name, .Enum_Literal:
case .Invalid, .Integer, .Float, .String, .Bool, .None, .Undefined, .Name:
}
}
}
@@ -1331,6 +1331,9 @@ infer_compound_expr :: proc(
case .Undefined:
return types.INVALID
case .Enum_Literal:
if expr.left != ast.INVALID_EXPR {
_ = infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
}
return types.INVALID
case .Address:
child := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
@@ -3256,29 +3259,45 @@ build_compound_expr :: proc(
)
return invalid_hir_expr(checker, expr.span, id, expected)
case .Enum_Literal:
// A bare enum literal in a tagged-union context constructs a variant. Only a
// void-payload variant can be built this way (it has no value); a payload variant
// must use `T{ variant = ... }`. (`.variant{...}` payload construction is the
// milestone-23 error-channel form.)
if types.is_tagged_union(expected, store) {
index, field, found := find_struct_field(checker, expected, expr.name)
if !found {
id := source.addf(checker.diagnostics, expr.span, "unknown variant '.%s' on '%s'", symbol_text(checker, expr.name), type_label(checker, expected))
return invalid_hir_expr(checker, expr.span, id, expected)
}
if !types.is_void(field.type) {
id := source.addf(checker.diagnostics, expr.span, "variant '.%s' on '%s' needs a payload; only void variants can be built from a bare '.%s'",
symbol_text(checker, expr.name), type_label(checker, expected), symbol_text(checker, expr.name))
return invalid_hir_expr(checker, expr.span, id, expected)
}
values := make([]hir.Expr_Id, 1, checker.allocator)
values[0] = hir.INVALID_EXPR
if expr.left == ast.INVALID_EXPR {
if !types.is_void(field.type) {
id := source.addf(checker.diagnostics, expr.span, "variant '.%s' on '%s' needs a payload; only void variants can be built from a bare '.%s'",
symbol_text(checker, expr.name), type_label(checker, expected), symbol_text(checker, expr.name))
delete(values, checker.allocator)
return invalid_hir_expr(checker, expr.span, id, expected)
}
values[0] = hir.INVALID_EXPR
} else {
if types.is_void(field.type) {
id := source.addf(checker.diagnostics, expr.span, "void variant '%s' takes no value", symbol_text(checker, expr.name))
delete(values, checker.allocator)
return invalid_hir_expr(checker, expr.span, id, expected)
}
values[0] = build_nested_expr(checker, expr.left, locals, global_reads, calls, field.type, pkg, file)
values[0] = coerce_expr(checker, values[0], field.type, checker.module.exprs[values[0]].span)
}
return add_hir_expr(checker, hir.Expr{
kind=.Struct, span=expr.span, type=expected, args=values, integer=i64(index),
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
if expr.left != ast.INVALID_EXPR {
id := source.addf(
checker.diagnostics,
expr.span,
"'.%s{...}' requires a tagged-union context",
symbol_text(checker, expr.name),
)
return invalid_hir_expr(checker, expr.span, id, expected)
}
if !types.is_enum(expected, store) {
id := source.addf(
checker.diagnostics,