contextual void construction
This commit is contained in:
@@ -1984,6 +1984,42 @@ infer_statements :: proc(
|
||||
case .Defer:
|
||||
deferred := [1]ast.Stmt_Id{statement.update}
|
||||
infer_statements(checker, deferred[:], locals, local_types, pkg, file, demanded, result, result_hint)
|
||||
case .Match:
|
||||
// The build pass desugars `match` to an if/else chain, but inference runs first
|
||||
// and must still visit the subject and arm bodies so calls there get specialized
|
||||
// (e.g. `match get()`). Mirror the `.For`/unwrap-`.If` capture handling.
|
||||
subject_type := infer_expr(checker, statement.expr, locals^[:], pkg, file, demanded, local_types)
|
||||
is_tagged := types.is_tagged_union(subject_type, &checker.module.types)
|
||||
for arm_id in statement.body {
|
||||
arm := checker.ast_module.statements[arm_id]
|
||||
if arm.kind != .Match_Arm {
|
||||
continue
|
||||
}
|
||||
for pattern in arm.patterns {
|
||||
_ = infer_expr(checker, pattern, locals^[:], pkg, file, demanded, local_types)
|
||||
}
|
||||
capture_start := len(locals^)
|
||||
if len(arm.captures) > 0 && is_tagged && len(arm.patterns) > 0 {
|
||||
capture := arm.captures[0]
|
||||
if capture != checker.sink_symbol {
|
||||
capture_type := types.INVALID
|
||||
pattern := checker.ast_module.exprs[arm.patterns[0]]
|
||||
if pattern.kind == .Enum_Literal {
|
||||
if _, field, ok := find_struct_field(checker, subject_type, pattern.name); ok {
|
||||
capture_type = field.type
|
||||
if arm.pointer_capture {
|
||||
// Mutability is best-effort here; the build pass finalizes
|
||||
// the exact pointer type and coerces the captured value.
|
||||
capture_type = types.pointer(&checker.module.types, field.type, true, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
append(locals, Infer_Local{name=capture, type=capture_type, declared=capture_type, statement=ast.INVALID_STMT})
|
||||
}
|
||||
}
|
||||
infer_statements(checker, arm.body, locals, local_types, pkg, file, demanded, result, result_hint)
|
||||
resize(locals, capture_start)
|
||||
}
|
||||
}
|
||||
}
|
||||
resize(locals, scope_start)
|
||||
@@ -3101,6 +3137,29 @@ 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
|
||||
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 !types.is_enum(expected, store) {
|
||||
id := source.addf(
|
||||
checker.diagnostics,
|
||||
|
||||
Reference in New Issue
Block a user