ADR-179: &[T] Is a Type of This Language, and It Is What a Run Crosses As

Status: Accepted Date: September 21, 2026 Answers: the former open-decisions.md’s may a build-time value cross as a view into what the build allocated — Option A Supersedes in part: ADR-302 D5’s &[T] is refused outside an extern "C" declaration. The &mut half of that sentence stands; the run does not Related: ADR-184 D1, D3 and D4 (the run is spelled ref Array[T]), ADR-311 D1 (a Vec[T] crosses in its view form), ADR-152 (Array[T, N], the form that was built instead and carries a length), ADR-094 D1 (the & a caller does not write) and D3 (the mut that is a declaration), ADR-282 D7 (no copy the program did not write), ADR-177 (a grammar’s result, and the sub-program that builds it)


1. Context

ADR-311 D1 says a build-time result crosses in its view form. Text has a view type (ref String), and a list can cross as an Array[T, N] (ADR-152) — but an Array[T, N] carries its length in its type, so a field of a struct can be one only where every value of that struct has a run of the same length. struct Section { settings: Vec[Setting] } is the shape both corpus grammars produce: Array[Setting, N] cannot type a field whose N differs per value, and a Vec owns memory a const cannot hold. What is missing is a view of a run whose length the value, not the type, carries.

Two more things want the same type. A binary asset has no result type an asset_bytes could have (ADR-310 reads text and refuses bytes that are not UTF-8), and Bytes (ADR-283 D19) owns its run. Three absences, one type.

And the type already exists at the C boundary. ADR-302 needs a run for an extern "C" declaration, where it lowers to an address beside a count, and refused it everywhere else on the reasoning that a run of elements whose length the type does not carry has no lowering here. That is true of a declaration and never of a view: a view of text is exactly such a run.

2. Decisions

D1 — &[T] is a view of a run, and it is a type wherever a type may stand.

Changed by ADR-184 D3 and D4: the run is spelled ref Array[T]; & is not in the language, and only the spelling moved.

It lowers to Rust’s own &[T], a fat pointer that carries its length — which is the half a Vec and an Array[T, N] also carry and a C declaration does not. .len(), xs[i], xs[i].field and for x in xs read one.

Two writers for one spelling, which is the arrangement ADR-302 chose: inside an extern "C" declaration ref Array[T] is an address beside a count, and everywhere else it is Rust’s &[T]. ref mut Array[T] and ref mut T stay the boundary’s alone, refused with NK1158 — a position this language may write through is declared mut name: T (ADR-094 D3), and that half of ADR-302 D5 is not touched.

D2 — What a body owns does not go into one, and the refusal says which line is which.

A ref Array[T] points at a run somebody else keeps. A Vec[T] a body just built is not one, and there is no & the compiler may write for it: a struct outlives the expression that fills it, so the view would point at something already gone (ADR-282 D7 — no copy and no borrow the program did not write).

A parameter is the case where the & is the compiler’s (ADR-094 D1): the callee reads and the caller keeps, so total(xs) for an xs: Vec[i64] needs no word, exactly as count(dna) does for a String against a ref String. The two look identical on the page, which is why the other one is NK1179 and not a fit that quietly holds.

And the value is spelled against the declaration. The same computed list is [1, 2, 3] against an Array[i64, 3] and a view of it against a ref Array[i64], and nothing in the value says which — so the crossing walks the type beside it, down through a struct’s fields and a variant’s payload, and writes the & exactly where a slice was declared.

D3 — At build time the sub-program owns what the program views.

A grammar runs by compiling the parser it generates (ADR-177 D1), and a parser builds a Vec. So in the sub-program every ref Array[T] field is written back as the Vec[T] it is a view of, and the dump — generated from the program’s declaration — reads a run either way.

That is the crossing rather than a disagreement: the sub-program is ADR-311 D1’s growable side and the program is its fixed one, which is the record’s own sentence read at two ends of one build.

D4 — A rule’s action may not build a struct whose field is a view of a run.

The same rule as D2, at the one place where this checker knows nothing about the value: an action’s bindings come from the parse. So inside an action anything that is not already a view is NK1179, and the way out names Vec[T] — because write a ref is not a thing anybody can do on a grammar line.

What a rule may hand back is the run itself, and that is the crossing the corpus wanted: entry rule file -> Vec[Setting] reaching comptime SETTINGS: ref Array[Setting].

3. Consequences

4. What this does not decide

This site is open source. Improve this page.