refactor(ir): extract CoercionResolver (conversions.zig) for coercion planning (A4.3 step 2)

Coercion classification now lives in src/ir/conversions.zig behind a *Lowering
facade (CoercionResolver), mirroring CallResolver / GenericResolver /
ProtocolResolver. Two pure classifiers:
- classify(src, dst) -> CoercionPlan (15 kinds: no_op / unbox_any / box_any /
  closure_to_fn_reject / tuple_elementwise / optional_unwrap / void_to_optional /
  optional_wrap / erase_protocol / int_to_float / float_to_int / ptr_int_bitcast /
  widen / narrow / none) — the built-in coercion ladder.
- classifyXX(src, dst) -> XXPlan (unbox_any / no_op / erase_protocol /
  protocol_to_pointer / coerce) — the xx-operator head.

coerceToType and lowerXX now `switch (classify…)` then emit; branch order
mirrors the originals exactly and every arm reproduces the prior lowering — the
f32/f64 Any match dispatch, buildProtocolErasure (lowerXX) vs buildProtocolValue
(coerceToType), tuple/optional recursion, and the user-Into fallback + pointer
materialization + recursion-guard/diagnostics (which stay in lowerXX /
tryUserConversion). IR emission stays entirely in Lowering; the classifiers are
pure. lowerXX keeps the operand's lowered Ref type as src_ty. `.none` means no
built-in applies (pass through; the Into fallback runs) — no silent default.

New pub: isFloat / isIntEx / typeBitsEx / resolveConcreteTypeName (the classifier
reads them); coercionResolver() accessor. lower.zig net -54 lines.

conversions.test.zig drives CoercionResolver directly: the full classify ladder
(no-op, Any box/unbox, widen/narrow, int<->float, ptr<->int, optional
wrap/unwrap, void->optional, tuple, closure-reject, .none for two unrelated
structs), erase_protocol for a concrete source, and classifyXX (all 5 kinds incl.
protocol-to-pointer vs coerce and pointer-materialization -> coerce).

zig build, zig build test, tests/run_examples.sh (357/0) all green — no .ir churn.
This commit is contained in:
agra
2026-06-02 22:45:56 +03:00
parent 50dd2cc3d8
commit f3bda369f6
4 changed files with 377 additions and 175 deletions

View File

@@ -11,6 +11,7 @@ pub const expr_typer = @import("expr_typer.zig");
pub const calls = @import("calls.zig");
pub const generics = @import("generics.zig");
pub const protocols = @import("protocols.zig");
pub const conversions = @import("conversions.zig");
pub const semantic_diagnostics = @import("semantic_diagnostics.zig");
pub const TypeId = types.TypeId;
@@ -47,6 +48,8 @@ pub const CallResolver = calls.CallResolver;
pub const CallPlan = calls.CallPlan;
pub const GenericResolver = generics.GenericResolver;
pub const ProtocolResolver = protocols.ProtocolResolver;
pub const CoercionResolver = conversions.CoercionResolver;
pub const CoercionPlan = conversions.CoercionResolver.CoercionPlan;
pub const compiler_hooks = @import("compiler_hooks.zig");
pub const emit_llvm = @import("emit_llvm.zig");
@@ -72,6 +75,7 @@ pub const expr_typer_tests = @import("expr_typer.test.zig");
pub const calls_tests = @import("calls.test.zig");
pub const generics_tests = @import("generics.test.zig");
pub const protocols_tests = @import("protocols.test.zig");
pub const conversions_tests = @import("conversions.test.zig");
pub const type_bridge_tests = @import("type_bridge.test.zig");
pub const emit_llvm_tests = @import("emit_llvm.test.zig");
pub const jni_descriptor_tests = @import("jni_descriptor.test.zig");