ffi any_to_string handles optionals — make-green

Closes the optional-through-Any gap that test 178 pinned.

Stdlib (`library/modules/std.sx`):
- New `optional_to_string :: (o: $T) -> string` returns `"null"`
  when the optional is None, otherwise recurses through
  `any_to_string` on the unwrapped inner value. Per-shape
  monomorphisation re-emits this for each concrete `?T`.
- `any_to_string` grows a `case optional:` arm that dispatches
  through `cast(type) val` (same shape as `case struct:` etc.).
  The cast picks up the dynamic optional type from the Any tag.

Compiler (`src/ir/lower.zig`):
- `resolveTypeCategoryTags` recognises "optional" as a dynamic
  category, scanning the TypeTable for `info == .optional`. The
  type-switch dispatch then routes any ?T tag into the optional
  arm.

IR snapshots regenerated where the optional addition shifted
constant pool / string numbering: 142, ffi-objc-call-06,
ffi-objc-dsl-07. 218/218 (test 178 included).

The variadic auto-unwrap in `packVariadicCallArgs` stays in
place — direct `print(opt)` calls still flow through it. The new
arm closes the gap for struct fields, slice elements, and any
other path that boxes an optional before stringifying.
This commit is contained in:
agra
2026-05-28 07:51:44 +03:00
parent 54e404bca1
commit ce77867566
5 changed files with 530 additions and 524 deletions

View File

@@ -298,6 +298,11 @@ enum_to_string :: (u: $T) -> string {
result; result;
} }
optional_to_string :: (o: $T) -> string {
if o == null { return "null"; }
return any_to_string(o!);
}
any_to_string :: (val: Any) -> string { any_to_string :: (val: Any) -> string {
result := "<?>"; result := "<?>";
type := type_of(val); type := type_of(val);
@@ -313,6 +318,7 @@ any_to_string :: (val: Any) -> string {
case array: result = array_to_string(cast(type) val); case array: result = array_to_string(cast(type) val);
case slice: result = slice_to_string(cast(type) val); case slice: result = slice_to_string(cast(type) val);
case pointer: result = pointer_to_string(cast(type) val); case pointer: result = pointer_to_string(cast(type) val);
case optional: result = optional_to_string(cast(type) val);
case type: { s : string = xx val; result = s; } case type: { s : string = xx val; result = s; }
} }
result; result;

View File

@@ -9491,7 +9491,7 @@ pub const Lowering = struct {
} }
// Dynamic categories: scan TypeTable for matching types // Dynamic categories: scan TypeTable for matching types
const Category = enum { @"struct", @"enum", @"union", slice, array, pointer, vector }; const Category = enum { @"struct", @"enum", @"union", slice, array, pointer, vector, optional };
const cat: ?Category = if (std.mem.eql(u8, name, "struct")) const cat: ?Category = if (std.mem.eql(u8, name, "struct"))
.@"struct" .@"struct"
else if (std.mem.eql(u8, name, "enum") or std.mem.eql(u8, name, "union")) else if (std.mem.eql(u8, name, "enum") or std.mem.eql(u8, name, "union"))
@@ -9504,6 +9504,8 @@ pub const Lowering = struct {
.pointer .pointer
else if (std.mem.eql(u8, name, "vector")) else if (std.mem.eql(u8, name, "vector"))
.vector .vector
else if (std.mem.eql(u8, name, "optional"))
.optional
else else
null; null;
@@ -9517,6 +9519,7 @@ pub const Lowering = struct {
.array => info == .array, .array => info == .array,
.pointer => info == .pointer or info == .many_pointer, .pointer => info == .pointer or info == .many_pointer,
.vector => info == .vector, .vector => info == .vector,
.optional => info == .optional,
}; };
if (matches) { if (matches) {
tags.append(self.alloc, @intCast(idx)) catch {}; tags.append(self.alloc, @intCast(idx)) catch {};

View File

@@ -892,5 +892,3 @@ declare ptr @object_getClass(ptr)
declare ptr @objc_getProtocol(ptr) declare ptr @objc_getProtocol(ptr)
declare i8 @class_addProtocol(ptr, ptr) declare i8 @class_addProtocol(ptr, ptr)

File diff suppressed because it is too large Load Diff

View File

@@ -953,5 +953,3 @@ entry:
store ptr %selN, ptr @OBJC_SELECTOR_REFERENCES_actualSelectorName, align 8 store ptr %selN, ptr @OBJC_SELECTOR_REFERENCES_actualSelectorName, align 8
ret void ret void
} }