address rvalue aggregates for field access

This commit is contained in:
2026-06-24 21:13:30 +02:00
parent c7e171c438
commit f6fc25a899
2 changed files with 71 additions and 30 deletions
+24 -30
View File
@@ -152,6 +152,24 @@ lower_location :: proc(state: ^State, expr_id: hir.Expr_Id, for_write := false)
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
if !hir_expr_is_location(state, expr_id) &&
types.is_runtime_value(expr.type, &state.hir_module.types) {
// rvalue aggregate (e.g. a by-value struct/array return) — spill into a
// function-scoped temporary so its fields/elements are addressable.
// Lifetime matches a local: valid until the function returns.
value := lower_nested_expr(state, expr_id)
slot := append_instruction(state, ir.Instruction{
op=.Alloca, span=expr.span, type=expr.type,
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
append_instruction(state, ir.Instruction{
op=.Store, span=expr.span, type=expr.type,
target=ir.INVALID_REF, a=slot, b=value,
diagnostic=source.INVALID_DIAGNOSTIC,
})
return slot
}
return ir.INVALID_INSTRUCTION
}
@@ -244,24 +262,12 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
diagnostic=source.INVALID_DIAGNOSTIC,
})
case .Slice:
// Array operands are addressed (locations) or spilled to a temporary
// (rvalues) by lower_location; other containers are slice/pointer values.
left_type := state.hir_module.exprs[expr.left].type
container: ir.Instruction_Id
if types.is_array(left_type, &state.hir_module.types) {
if hir_expr_is_location(state, expr.left) {
container = lower_location(state, expr.left)
} else {
value := lower_nested_expr(state, expr.left)
container = append_instruction(state, ir.Instruction{
op=.Alloca, span=expr.span, type=left_type,
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
append_instruction(state, ir.Instruction{
op=.Store, span=expr.span, type=left_type,
target=ir.INVALID_REF, a=container, b=value,
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
container = lower_location(state, expr.left)
} else {
container = lower_nested_expr(state, expr.left)
}
@@ -1085,21 +1091,9 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
}
iterable_value := ir.INVALID_INSTRUCTION
if types.is_array(iterable_type, &hir_module.types) {
if hir_expr_is_location(state, statement.expr) {
iterable_value = lower_location(state, statement.expr)
} else {
value := lower_expr(state, statement.expr)
iterable_value = append_instruction(state, ir.Instruction{
op=.Alloca, span=statement.span, type=iterable_type,
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
diagnostic=source.INVALID_DIAGNOSTIC,
})
append_instruction(state, ir.Instruction{
op=.Store, span=statement.span, type=iterable_type,
target=ir.INVALID_REF, a=iterable_value, b=value,
diagnostic=source.INVALID_DIAGNOSTIC,
})
}
// Address an array location, or spill an array rvalue to a
// temporary — both handled by lower_location.
iterable_value = lower_location(state, statement.expr)
} else {
iterable_value = lower_expr(state, statement.expr)
}