diff --git a/examples/100-closure-field-call-via-self-ptr.sx b/examples/100-closure-field-call-via-self-ptr.sx new file mode 100644 index 0000000..87eab7e --- /dev/null +++ b/examples/100-closure-field-call-via-self-ptr.sx @@ -0,0 +1,40 @@ +// Invoking a Closure-typed struct field as `self.field()` from a +// method whose receiver is `*Self`. The field access must auto-deref +// the pointer before extracting the closure value. + +#import "modules/std.sx"; + +Holder :: struct { + cb: Closure() = ---; + has: bool = false; + + set :: (self: *Holder, fn: Closure()) { + self.cb = fn; + self.has = true; + } + + // Direct invocation through *self. + call_direct :: (self: *Holder) { + if self.has == false { return; } + self.cb(); + } + + // Hoist-then-call form — must agree with the direct form. + call_hoisted :: (self: *Holder) { + if self.has == false { return; } + fn := self.cb; + fn(); + } +} + +ticks : s32 = 0; + +main :: () -> s32 { + h : Holder = .{}; + h.set(() => { ticks += 1; }); + + h.call_direct(); + h.call_hoisted(); + + return ticks; +} diff --git a/src/ir/lower.zig b/src/ir/lower.zig index e72d0b6..26e9299 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -4215,8 +4215,13 @@ pub const Lowering = struct { if (f.name == field_name_id and !f.ty.isBuiltin()) { const fti = self.module.types.get(f.ty); if (fti == .closure) { - // Extract closure from struct field - const closure_val = self.builder.structGet(obj, @intCast(fi), f.ty); + // structGet requires an aggregate value; if obj is *T, load through it first. + var agg = obj; + const oi = self.module.types.get(obj_ty); + if (oi == .pointer) { + agg = self.builder.load(obj, oi.pointer.pointee); + } + const closure_val = self.builder.structGet(agg, @intCast(fi), f.ty); const owned = self.alloc.dupe(Ref, args.items) catch unreachable; return self.builder.emit(.{ .call_closure = .{ .callee = closure_val, .args = owned } }, fti.closure.ret); } diff --git a/tests/expected/100-closure-field-call-via-self-ptr.exit b/tests/expected/100-closure-field-call-via-self-ptr.exit new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/tests/expected/100-closure-field-call-via-self-ptr.exit @@ -0,0 +1 @@ +2 diff --git a/tests/expected/100-closure-field-call-via-self-ptr.txt b/tests/expected/100-closure-field-call-via-self-ptr.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/expected/100-closure-field-call-via-self-ptr.txt @@ -0,0 +1 @@ +