Properties render as Swift computed `var`s. Each accessor is planned
independently as either a delegation to the GIR getter=/setter= method
or the uniform GValue machinery (g_object_get_property/_set_property).
Delegation is preferred and inherits the method's nullability and
ownership (e.g. Binding.source becomes Object? because get_source is
nullable, where the GValue path produced a trap-prone non-optional
Object). It is chosen only when it yields one consistent Swift type;
otherwise both accessors fall back to GValue. GValue is also the
fallback for pure-GObject properties with no dedicated C accessor.
Enum/flags GValue getters bridge gint/guint to the Swift raw value via
numericCast; a bare cast would fail to compile on any enum-bearing tier.
Construct-only properties render read-only. Interface properties become
{ get } / { get set } requirements. GObject's fundamental G_TYPE_*
constants are emitted into its support file.
Adds 17 PropertyGenerationTests (incl. 5 delegation cases) and 2 runtime
smoke tests exercising a GValue round-trip and delegated getFlags() /
nullable getSource() off a real GBinding.
GIR caller-allocates out-params (char *outbuf, gunichar *result) require
the caller to allocate and size the buffer, unlike callee-allocates T**
out-params where the callee fills in the pointee. The out-param
marshalling declared a single Swift scalar and passed its address, which
is correct only for the callee-allocates shape; for caller-allocates, C
wrote buffer payload past the one-element slot (g_unichar_fully_decompose)
or the payload was reinterpreted as a pointer and dereferenced
(g_unichar_to_utf8, segfault). GIR carries no buffer-size field, so these
are now skipped rather than generated. The guard also reclassifies
time_val_from_iso8601/signal_query/type_query from plainRecord to the
accurate caller-allocates reason.
Add smoke tests exercising boxed-record lifetime (copy-on-borrow,
adopt-on-full, init(retaining:), isolated deinit over thousands of alloc/free
cycles), out-param tuple returns, enum returns, bitfield arguments, and GError
bridging on both the success and throwing paths — proving each marshalling
category reaches real GLib/GObject correctly at runtime.
Boxed records (C4): resolve each record's copy/free function from the GIR
copy-function/free-function attribute, else its own ref/copy and unref/free
method, and render init(retaining:) plus an isolated deinit. The deinit is
isolated because the package's default MainActor isolation makes accessing the
non-Sendable pointer from a nonisolated deinit a hard error. The registry uses
the same resolution so transfer=none returns copy instead of adopting a
borrowed pointer. This supersedes the earlier deferral: the hypothesised
OpaquePointer/Sendable barriers either did not hold or were solvable.
Interfaces (C5): plan each interface method through planMethod and render it as
a protocol requirement (no body); the conforming class supplies the C call.
- Deleted CodeGen+Signal.swift entirely
- Replaced CodeGen.swift with minimal shim (scaffolding only)
- Removed returnType compat shims from IRModel.swift
- Simplified Main.swift to always use plan engine
- Removed single-GIR path (parser debugging only)
- Removed --engine=plan flag (plan engine is now default)
- Updated CLI tests and help text
- 124 tests pass, Gate 1 PASSES
Generated output: 271 types (GLib: 215 value types, GObject: 56 types incl. 30 classes)
Class wrappers with cross-module inheritance, ownership inits, and override.
Methods/functions deferred to Phase C (needs C enum bridging).
GObject: 56 bound types (30 class wrappers + 26 value types), up from 26.
GLib: 215 bound types (no classes - pure C library).
Gate 1 now PASSES with class wrappers, zero compile errors.