DEV Community

COMMENTERTHE9
COMMENTERTHE9

Posted on • Originally published at cx-lang.com

Cx Dev Log — 2026-05-21

Cx Dev Log — Breaking Through the When-Block Hurdle

The introduction of when block IR lowering has marked a significant checkpoint for Cx, as seen in a 426-line commit to submain. This brings us closer to addressing hard blocker H3, an integral step for the 0.1 release. The JIT parity matrix saw an uplifting shift from 110 to 120 passing fixtures, thanks in part to resolving a compound-assign narrowing issue. Here's how it came together.

How when Lowering Works

We've integrated a chained-decision control flow graph (CFG) for when block lowering, aligning it with the strategy used for lower_logical in handling AND/OR short-circuit evaluation. The process for each when arm is as follows:

  • Patterns such as Literal, Range, and TBool-unknown trigger Compare instructions, followed by a Branch directing to the arm body or the next block.
  • Catchall arms execute a direct jump to their body.
  • Statement-style when blocks unify arm bodies using merge_fallthroughs.
  • Expression-style when blocks employ a typed block parameter for merging.

Why not go for table-dispatch or SSA phi-node based merges? There's a simple reason: these alternatives would necessitate additional IR infrastructure, useful only for the when functionality. By leveraging existing patterns, not only do we simplify, but we also ensure seamless integration with Cranelift's multi-way backend branching. For version 0.1, maximizing efficiency and reuse was the clear path forward.

TBool Unknown Matching

Handling the TBool unknown case required a workaround: comparing the scrutinee against ConstInt(I8, 2), employing Cast(I8 -> scrutinee.ty), then performing a Compare(Eq). This ingenious method skirts the IR validator's constraints without venturing into literal semantics for the TBool, an issue still tabled for future discussion. Presently, focusing on wire value-based pattern matching sets a solid foundation.

Challenges with EnumVariant Arms

EnumVariant arms remain a sticking point—better termed a deliberate limitation at this stage. The lowering process flags these as structured errors detailing the enum and variant. Until we tackle Enum IR lowering, fixtures such as t22, t27, and t28 will remain marked by the SKIP status. It’s a postponed target, slated for post-0.1 attention.

Compound-Assign Narrowing Etched Out

Another noteworthy update comes with commit e4c9202, a fix that rectifies a gap in the +=, *=, etc., compound-assign paths. Previously, these routes missed narrowing numeric literals against target types, causing IR-validator Verifier errors when handling narrow-int fields. By extracting the target type from all SemanticLValue variants and invoking insert_cast_if_needed for numeric interactions, we achieved a corrective balance. This alignment nudged tests like t41_compound_assign_dot and t109_struct_field_overflow from SKIP to PASS.

Hard Blocker Status and What Lies Ahead

We’ve made substantial headway, closing three hard blockers in two days:

  • H1: closed (May 20)
  • H2: closed (May 20)
  • H3: substantially addressed (May 21, Option A scope)
  • H5: closed (May 20)

H4 is the next frontier, encompassing features such as CX-91, CX-94, and CX-34 that are still pending. As we shift focus to the remaining 62 SKIP fixtures, tackling Enum IR lowering and other unaddressed constructs emerges as a priority. Immediate targets aren't crystal clear—each demands dissecting to diagnose specific barriers.

The task of evolving the submain-to-main merge looms large, as submain extends 181 commits beyond. This anticipated merge has been on the horizon since May 6, yet remains elusive. Today’s updates count as merely additional steps towards this pivotal integration.


Follow the Cx language project:

Originally published at https://cx-lang.com/blog/2026-05-21

Top comments (0)