Ruta graveolens  ·  notes from a language experiment  ·  cultivated since 2025

E0908: Slice frame array not supported

CodeCategoryStability
E0908ArrayPermanent

Explanation

The fixed-array-to-slice coercion materializes a two-word view — the address of element 0 and the length — and hands it to a borrow [T] parameter (7.2:12). A view strides by the element type's own compact size, while a frame-resident array still keeps one full 8-byte slot per leaf, so the view is exact exactly when the element's compact stride equals its slot stride — and, inside an aggregate element, its field and element offsets agree too. E0908 refuses the coercion at the argument when they differ, naming the element type (7.2:14). They differ for an element with a leaf narrower than a slot — bool, i8/u8, i16/u16, i32/u32, and f32, whose compact stride is four bytes against an eight-byte slot — for an enum, whose tag is narrowed, and for any struct or array holding one of those. They agree for every leaf that fills its slot: i64, u64, pointers, and f64. A float is loaded and stored by a floating-point instruction rather than moved as an opaque slot, but an access kind moves no byte, so [f64] coerces like [i64] does; so does a struct or array built only from slot-filling leaves, however many fields it has. An empty array is exempt, because a zero-length view's pointer word is never dereferenced. This is a transitional limit of the current implementation tracked by RUE-1595, not a property of the slice type: it is lifted when arrays adopt the compact element representation. An operand that is not a whole array place, or whose element type merely converts to the slice's, is a different failure — a type mismatch under 7.2:13.

Likely cause

A local array whose element has a narrower-than-slot leaf was passed to a borrow [T] parameter, as in head(borrow xs) for xs: [i32; 3]. Until the restriction is lifted, either widen the element so every leaf fills its slot — [i64; N] and [f64; N] both coerce, and so does an element struct whose every field is slot-filling — or take the fixed array itself as a borrow [T; N] parameter, which passes one pointer and needs no view. An empty array of any element type still coerces.

Examples

Borrow a narrow-element frame array as a slice

fn head(borrow s: [i32]) -> i32 { s[0] }

fn main() -> i32 {
    let xs: [i32; 3] = [42, 1, 2];
    head(borrow xs)
}

Coerce a slot-filling element type

fn head(borrow s: [i64]) -> i32 { @intCast(s[0]) }

fn wide(borrow s: [f64]) -> i32 { @float_to_int(s[0] * 2.0) }

fn main() -> i32 {
    let xs: [i64; 3] = [42, 1, 2];
    let ys: [f64; 3] = [1.5, 2.5, 3.5];
    head(borrow xs) - wide(borrow ys)
}

References