Mehdi Akiki
Rust Failure Atlas / Language and diagnostics

RFA-456 · Case file with fixtures · Case 428 of 694 · Compiler evidence

A Fixed-array Pattern Must Match the Array Length

Array length is part of the type, and a slice-style pattern without .. states an exact arity. Match every position or add a deliberate rest pattern when only a prefix or suffix matters.

Reviewed
Rust
Rust 1.98.1, edition 2024
Targets
all Rust targets
Profiles
dev, release, test

Direct answer

What this Rust failure means

Why it happens
Array length is part of the type, and a bracket pattern without a rest component claims an exact arity rather than a prefix.
First discriminating check
Compare the array's N with explicit pattern positions, then preserve exactness or add .. only when remaining elements are semantically irrelevant.

I destructured [10, 20, 30, 40] with [first, second], intending to take only the prefix. Rust produced E0527 because a bracket pattern without .. states an exact number of elements.

The failing fixture is an array-length contract, not a runtime bounds check. The compiler already knows the value has four elements from its type.

Array length belongs to the type

Rust types [T; 2] and [T; 4] are different. A pattern [a, b] mirrors the complete shape of a two-element array. It does not mean “bind the first two and silently ignore the rest.”

The E0527 explanation recommends making the pattern consistent with the array size or using .. for additional elements.

This catches stale destructuring when a fixed protocol field, SIMD lane group, or test vector changes length.

Add rest syntax for a deliberate prefix

The repaired fixture writes:

let [first, second, ..] = values;

Now the pattern states that the first two positions matter and every remaining position may contain anything. Because the array length is known to be four, the pattern is irrefutable here.

I use [.., last] for a suffix and [first, middle @ .., last] when the remainder itself must be borrowed or inspected in a refutable slice match.

Exact patterns are useful migration alarms

Replacing every array pattern with .. would lose an important check. If all four bytes form a wire header, [version, flags, size_hi, size_lo] records exact layout and should fail when the type changes.

If only a prefix is semantically relevant, the rest pattern is honest. I choose based on whether length evolution should force review.

This is similar to explicit struct fields versus a struct rest pattern.

Arrays and slices differ at compile time

For an array, length is statically known. For a slice &[T], runtime length varies, so [first, second] is a refutable pattern matching only slices of length two.

The slice-pattern Reference covers both forms, but context changes whether a pattern can be proven impossible or must be checked at runtime.

I inspect whether an API gives [T; N], &[T], or Vec<T> before selecting destructuring syntax.

Rest syntax does not allocate

.. in a pattern is not collection or copying. It describes unmatched positions. When bound as rest @ .. through a borrowed slice, the remainder is another slice view.

This makes prefix parsers concise, but I still validate length through the pattern and handle the non-matching arm. I do not index first and hope the input is long enough.

For a fixed array known to be large enough, the compiler can prove the prefix exists.

Const generics change what can be destructured

A function generic over [T; N] may not know that a particular fixed pattern is valid for every N. Array methods such as first, split_first, iteration, or conversion can better express an operation generic over length.

I avoid forcing destructuring when the algorithm's real contract is “any non-empty sequence.” The type signature and control flow should state that precondition.

Ownership follows element bindings

Destructuring an owned array by value can move non-Copy elements out. Matching a borrowed array produces references through binding modes. Rest syntax does not by itself decide ownership.

After fixing E0527, I check whether later code needs the array or ignored elements. A compiling shape repair can still introduce unwanted moves if bindings changed.

My E0527 checklist

When the array comes from a conversion such as slice.try_into(), I keep the length validation close to that conversion. After it succeeds, exact destructuring is a strong statement and should not normally need ... If I immediately ignore most positions, the conversion to a fixed array may not be buying useful certainty. A borrowed slice prefix or a small parser helper can express the narrower need while preserving the caller's original buffer and avoiding unnecessary copies.

  • What is the array's exact [T; N] type?
  • Does the pattern intend exact arity or only a prefix/suffix?
  • Should a length change force this code to be reviewed?
  • Would .. hide meaningful protocol positions?
  • Is the input actually a runtime-length slice?
  • Does generic N require a method-based approach?
  • Will element bindings copy, move, or borrow?

The core principle is that fixed arrays carry their size in the type and exact patterns preserve that fact. I add .. only as an explicit statement that remaining positions are outside this operation's concern, not as a reflex to silence the compiler.