ADR-135: A List Literal Is [1, 2, 3], the Empty One Takes Its Type From Its First Use, and a [ at the Start of a Line Begins a Literal

Status: Accepted Date: September 19, 2026 Related: ADR-285 (a literal no use constrains takes the first type that holds it), ADR-298 D1 (what a reserved word costs), ADR-291 (a let takes one name or a flat tuple), Part I 2.2 and 4.5

1. Context

A list is the language’s most-written container, and without a literal it can only be built a push at a time. The grammar had no [ in expression position at all, so the syntax is free and the only cost of taking it is the two questions below.

Two things are the owner’s rather than the compiler’s.

What [] is. An empty literal carries no element type. Either it takes one from a later use — which is ADR-285’s rule for a number literal applied to a container — or it is refused with a request for the type.

What a [ at the start of a statement means. After an expression statement, a line beginning [ is either an index of what came before or a new literal. Rust reads it as an index and needs a ;; JavaScript reads it the same way and is famous for it.

2. Decisions

D1 — [a, b, c] is a list, and [] is an empty one.

let xs = [1, 2, 3]
let empty: Vec[i64] = []
let rows = [Row(id: 1), Row(id: 2)]

Changed by ADR-152 D4: a literal standing where its use asks for an Array[T, N] is that array; a literal with no such use is a Vec[T].

The elements are expressions, a trailing comma is allowed, and the type is Vec[T] where T is what the elements agree on. A literal whose elements do not agree on a type is NK1154, naming the two, exactly as a let with an annotation is; where an element has no type yet — a bare 1 fits every numeric type — it names the kind, so [1, "two"] is refused here.

D2 — [] takes the type from the first use, and is refused where none exists.

This is ADR-285’s rule one level up: a number literal with nothing beside it is a value rather than a type, and the first use that needs a type is what gives it one. So let xs: Vec[i64] = [] is an i64 list, let mut xs = [] followed by xs.push(1) is an i64 list, and let xs = [] with no use at all is NK1153 — this empty list has no element type; write one, or give it a first element. The question is asked once the whole body has been walked, because the use that answers it stands after the let.

Refused and not guessed. A default element type would be a type nobody wrote, and the one thing this checker may never do is claim something the program does not say (Part III C.4).

D3 — A [ at the start of a line begins a literal.

An index is written on the line its receiver is on. A statement that begins with [ is a list literal, always, and there is no lookahead and no ; to write.

An index across a line break is a shape nobody writes, which is the whole argument: the alternative costs every reader of every list literal a moment of doubt, to keep working a line nobody has typed. Rust and JavaScript both chose the other way and both have the footgun in their style guides.

3. Consequences

4. What this does not decide

This site is open source. Improve this page.