Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified self-host/ir_driver
Binary file not shown.
44 changes: 44 additions & 0 deletions self-host/ir_emitter_core.pith
Original file line number Diff line number Diff line change
Expand Up @@ -3897,11 +3897,53 @@ fn ir_emit_assign_stmt(node: Node):
ir_var_regs.insert(name, r)
ir_emit("store " + ir_resolve_storage_name(name) + " " + r.to_string())

# Assign to a struct field target: `obj.field = value`. Returns false if the
# target is not a known struct field (so the caller falls back to other forms).
fn ir_emit_field_assignment(target_idx: Int, value_idx: Int) -> Bool:
target := get_node(target_idx)
if target.kind != "field_access" or target.children.len() == 0:
return false
fname := node_value(target_idx)
recv_idx := target.children[0]
lookup_key := ir_field_lookup_key(recv_idx, fname)
if not ir_struct_field_index_lookup.contains_key(lookup_key):
return false
field_index := ir_unpack_field_index(ir_struct_field_index_lookup[lookup_key])
obj_r := ir_expr(recv_idx)
mut value_type := ir_checked_struct_field_type(recv_idx, fname)
if value_type.len() == 0:
value_type = ir_infer_type(value_idx)
value_r := ir_emit_value_for_target(value_idx, value_type)
ir_emit("sstore " + obj_r.to_string() + " " + field_index.to_string() + " " + value_r.to_string())
return true

# Compound assign to a struct field: `obj.field += value` (and -=, *=, /=).
fn ir_emit_field_compound_assignment(target_idx: Int, value_idx: Int, compound_op: String) -> Bool:
target := get_node(target_idx)
if target.kind != "field_access" or target.children.len() == 0:
return false
fname := node_value(target_idx)
recv_idx := target.children[0]
lookup_key := ir_field_lookup_key(recv_idx, fname)
if not ir_struct_field_index_lookup.contains_key(lookup_key):
return false
field_index := ir_unpack_field_index(ir_struct_field_index_lookup[lookup_key])
obj_r := ir_expr(recv_idx)
cur := ir_reg()
ir_emit_named_field_access(cur, obj_r, lookup_key, fname, ir_checked_struct_field_type(recv_idx, fname))
rhs := ir_expr(value_idx)
res := ir_reg()
ir_emit_simple_binary(res, compound_op, cur, rhs)
ir_emit("sstore " + obj_r.to_string() + " " + field_index.to_string() + " " + res.to_string())
return true

fn ir_emit_compound_assignment(node: Node):
op := node.value
if op == "=" and node.children.len() >= 2:
if ir_emit_index_assignment(node.children[0], node.children[1]):
return
if ir_emit_field_assignment(node.children[0], node.children[1]):
return
tn := get_node(node.children[0])
name := tn.value
target_type := ir_checked_target_type(node.children[0], name)
Expand All @@ -3910,6 +3952,8 @@ fn ir_emit_compound_assignment(node: Node):
return
compound_op := ir_compound_assignment_ir_op(op)
if compound_op.len() > 0 and node.children.len() >= 2:
if ir_emit_field_compound_assignment(node.children[0], node.children[1], compound_op):
return
tn := get_node(node.children[0])
name := tn.value
cur := ir_reg()
Expand Down
45 changes: 45 additions & 0 deletions tests/cases/test_struct_field_assign.pith
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# assigning to struct fields: locals, compound ops, through functions
# (reference semantics), and from methods via implicit self

struct Counter:
value: Int
label: String

struct Point:
x: Int
y: Int

impl Counter:
fn step():
self.value = self.value + 1

fn add(n: Int):
self.value += n

fn bump(c: Counter):
c.value = c.value + 100

fn main():
mut c := Counter(5, "hits")
c.value = 10
print("set: {c.value}")
c.value += 3
print("compound: {c.value}")
c.label = "changed"
print("label: {c.label}")

# mutation through a function persists (structs are shared handles)
bump(c)
print("after bump: {c.value}")

# mutation through methods (implicit self)
c.step()
c.step()
print("after steps: {c.value}")
c.add(20)
print("after add: {c.value}")

p := Point(1, 2)
p.x = 42
p.y = p.x + 1
print("point: {p.x},{p.y}")
7 changes: 7 additions & 0 deletions tests/expected/test_struct_field_assign.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set: 10
compound: 13
label: changed
after bump: 113
after steps: 115
after add: 135
point: 42,43
Loading