Files
sx/examples/1326-ffi-objc-arc-03-weak-property.sx
agra 4e942b5373 test: migrate examples to XXXX-category-name layout + split expected streams
Rename all example tests/companions to the XXXX-category-test-name scheme
(per-category 100-blocks: basic 0010, types 0100, ... errors 1000,
diagnostics 1100, ffi 1200, ffi-objc 1300, ffi-jni 1400, vectors 1500,
platform 1600). Companions and dir/C fixtures move in lockstep with their
parent test; #import/#source/#include paths rewritten to match.

Expected output now lives in examples/expected/ (a sibling dir of the
tests) split into three streams per the new convention:
  <name>.exit / <name>.stdout / <name>.stderr  (+ optional <name>.ir)

run_examples.sh rewritten: scans examples/ and issues/ for an
expected/<name>.exit marker, captures stdout and stderr separately (no
more 2>&1), compares each stream + exit + optional IR snapshot.

Behavior validated unchanged: every renamed test reproduces its prior
merged output + exit (diffs limited to file paths/basenames embedded in
diagnostics + traces, which correctly reflect the new names). Suite:
292 passed, 0 failed. 50-smoke.sx split + issue relocation + docs follow
in subsequent commits.
2026-06-01 19:05:15 +03:00

67 lines
2.1 KiB
Plaintext

// ffi-objc-arc-03 — #property(weak) on sx-defined class.
//
// Weak contract:
// - setter calls objc_storeWeak — does NOT retain.
// - getter calls objc_loadWeakRetained + autorelease — auto-nils
// if the target has been deallocated.
// - -dealloc calls objc_destroyWeak on each weak ivar.
//
// Observation: assign a target to the weak property. Drop the
// caller's strong reference. Read back via the weak getter — should
// be `null` (the target deallocated when its last strong ref
// dropped, and the weak slot auto-niled).
//
// Pre-M4.B: setter just stores the pointer (no storeWeak); getter
// reads the raw pointer (no loadWeakRetained). After target's
// release, the slot points at freed memory — the read returns the
// stale pointer (not null). The test catches this by comparing the
// read result to null.
#import "modules/std.sx";
#import "modules/allocators.sx";
#import "modules/std/objc.sx";
#import "modules/compiler.sx";
SxWeakTarget :: #objc_class("SxWeakTarget") {
#extends NSObject;
tag: s32;
alloc :: () -> *SxWeakTarget;
}
SxWeakHolder :: #objc_class("SxWeakHolder") {
#extends NSObject;
target: *SxWeakTarget #property(weak);
alloc :: () -> *SxWeakHolder;
}
main :: () -> s32 {
inline if OS == .macos {
gpa := GPA.init();
tracker := TrackingAllocator.init(xx gpa);
push Context.{ allocator = xx tracker, data = null } {
holder := SxWeakHolder.alloc();
target := SxWeakTarget.alloc();
holder.target = target;
target.release();
// After release: target's refcount → 0 → target deallocates.
// With weak: holder.target should read as null (auto-niled).
// Without weak: holder.target reads as the stale pointer.
read_back := holder.target;
if read_back != null {
print("FAIL: weak property didn't auto-nil after target dealloc\n");
return 1;
}
holder.release();
}
print("weak property: ok\n");
}
inline if OS != .macos {
print("skipped (not macos)\n");
}
0;
}