fix: resolve closure/fn-pointer struct-field call types (issue 0201)
Calling a closure or function-pointer value stored in a struct data field (`box.run(args)`) typed the call as 'unresolved': value returns marshalled as garbage, failable fields could not be try/catch-ed. Lowering already dispatched these (call_closure / call_indirect); only CallResolver.plan lacked a field-access arm. Add a closure/fn-pointer field arm to plan (before the instance-method check, mirroring lowering's precedence — a closure-typed field shadows a same-named method) and extend the lowering closure-field arm to also handle bare .function fields via call_indirect. Lock: examples/closures/0315-closures-struct-field-call.sx.
This commit is contained in:
@@ -990,6 +990,28 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
|
||||
} else self.alloc.dupe(Ref, args.items) catch unreachable;
|
||||
return self.builder.emit(.{ .call_closure = .{ .callee = closure_val, .args = owned } }, fti.closure.ret);
|
||||
}
|
||||
// Bare function-pointer field (`fp: (T) -> R`, no env) —
|
||||
// load the field value and call it via `call_indirect`,
|
||||
// mirroring the bare-identifier / global fn-pointer paths
|
||||
// (ctx prepend gated on the fn-ptr's own ABI).
|
||||
if (fti == .function) {
|
||||
var agg = obj;
|
||||
const oi = self.module.types.get(obj_ty);
|
||||
if (oi == .pointer) {
|
||||
agg = self.builder.load(obj, oi.pointer.pointee);
|
||||
}
|
||||
const fp_val = self.builder.structGet(agg, @intCast(fi), f.ty);
|
||||
// Coerce user args to the fn-ptr's param types (issue 0186).
|
||||
coerceClosureCallArgs(self, args.items, fti.function.params);
|
||||
var final_args = std.ArrayList(Ref).empty;
|
||||
defer final_args.deinit(self.alloc);
|
||||
if (self.fnPtrTypeWantsCtx(f.ty)) {
|
||||
final_args.append(self.alloc, self.current_ctx_ref) catch unreachable;
|
||||
}
|
||||
final_args.appendSlice(self.alloc, args.items) catch unreachable;
|
||||
const owned = self.alloc.dupe(Ref, final_args.items) catch unreachable;
|
||||
return self.builder.emit(.{ .call_indirect = .{ .callee = fp_val, .args = owned } }, fti.function.ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user