test(ir): lock coercion forms before A4.3 extraction (A4.3 scaffolding step 1)

Test-first scaffolding ahead of extracting src/ir/conversions.zig — no code
change to the coercion targets (lowerXX / coerceToType / coerceOrErase /
buildProtocolErasure / tryUserConversion / failable-adapter selection).

Adds 4 .ir snapshots (first .ir for 01xx/09xx/10xx), each captured surgically
via `sx ir | normalize_ir`, path-free, idempotent, and print-free at IR-gen time
(0114-types-build-block-convert was rejected — it prints `--- void / 0 args ---`
+ sx source at IR-gen):
- 0107-types-int-cmp-in-float-ternary   numeric int<->float coercion
- 0903-optionals-optional-roundtrip     optional wrap/unwrap
- 0904-optionals-any-to-string-optional xx unbox_any + optional
- 1004-errors-try                       error-channel adapter/coercion

Protocol erasure + user Into are already pinned by the 04xx snapshots
(0400/0413/0414/0416); duplicate-conversion rejection by the 0410/0411/0412
anchors.

Adds 1 unit test via the public surface (no new exposure, mirroring A4.1/A4.2
sub-step 1): optionalOfFlattened — the optional wrap/flatten coercion rule
(T -> ?T; ?T -> ?T, never ??T; contrasted with the non-flattening optionalOf).
The lowerXX/coerceToType/coerceOrErase/buildProtocolErasure decisions are private
+ emission-bound, so their CoercionPlan unit tests land with the extracted module
in sub-step 2.

zig build, zig build test, tests/run_examples.sh (357/0) all green.
This commit is contained in:
agra
2026-06-02 22:32:01 +03:00
parent 137285f33d
commit 50dd2cc3d8
5 changed files with 14171 additions and 0 deletions

View File

@@ -879,3 +879,27 @@ test "protocols: registerProtocolDecl builds the dispatch method table" {
try std.testing.expect(info.methods[1].ret_is_self);
try std.testing.expectEqual(module.types.ptrTo(.void), info.methods[1].ret_type);
}
// ── A4.3 test-first scaffolding: coercion planning ───────────────────
// Lock the one coercion-plan decision reachable via the existing public
// surface — the optional wrap/flatten rule — before coercion planning moves to
// `src/ir/conversions.zig`. The lowerXX / coerceToType / coerceOrErase /
// buildProtocolErasure decisions are private + emission-bound, so their
// CoercionPlan unit tests land with the extracted module in sub-step 2 (as the
// generics/protocols plan tests landed with their modules); behavior is locked
// here by the new `.ir` snapshots.
test "conversions: optionalOfFlattened wraps once, flattening a nested optional" {
const alloc = std.testing.allocator;
var module = ir_mod.Module.init(alloc);
defer module.deinit();
var l = Lowering.init(&module);
const opt_s64 = module.types.optionalOf(.s64);
// Wrap a non-optional: T -> ?T.
try std.testing.expectEqual(opt_s64, l.optionalOfFlattened(.s64));
// Wrap an already-optional FLATTENS: ?T -> ?T (the coercion never builds ??T).
try std.testing.expectEqual(opt_s64, l.optionalOfFlattened(opt_s64));
// Contrast: the plain wrap does NOT flatten — ?T -> ??T (distinct type).
try std.testing.expect(module.types.optionalOf(opt_s64) != opt_s64);
}