Wado

WEP: NirExprKind::ArrayLiteral — a NIR-Materialized List Node

Context

NIR gives two of the three aggregate constructors a first-class, analyzable value form: StructLiteral and TupleLiteral. Arrays were the missing third.

An array literal such as [1, 2, 3] as List<i32> did not reach NIR as a literal. Elaboration coerced it through a builder-trait path, so once that path was inlined the construction arrived as an imperative sequence over a fresh local — a with_capacity call bound by a Let, followed by N push statements. The fixed-shape const-array form re-materialized only at WIR.

The consequence was a blind spot: every NIR pass saw an array constant as opaque imperative mutation, not as a value. NIR could not deduplicate it, index into it at compile time, reason about its length, or globalize it. The capability existed one layer too late.

Decision

The node

NirExprKind::ArrayLiteral { elements }, shaped to match its sibling TupleLiteral. No element_type / array_type field: the node carries a type_id and the element type is recoverable from it, exactly as wir_build recovers a tuple's struct type. A redundant type field would be a second source of truth every clone and rewrite must keep in sync.

Where it comes from

lower emits the node: a [e0, e1, …] literal denotes an Array<T> of exactly its length, which the target's From<Array<T>> impl then consumes (Literal Coercion as From<Array<…>>). elements are expressions, not a constant-only payload: an ArrayLiteral evaluates them left to right, and const-ness unlocks the consumers rather than being a precondition of the node.

wir_build lowers ArrayLiteral to the existing WirInstr::ArrayNewFixed; no new WIR node. The downstream WIR passes that consume ArrayNewFixed (promote_constant_arrays_to_data, split_large_array_literals, rewrite_constant_array_indexing) key on what wir_build keeps emitting.

Consumers

ArrayLiteral is shared infrastructure — it pays for itself across passes rather than for one.

Consequences

Alternatives considered

See also