ADR-227: collect() Builds What the Place It Goes Into Declares

Status: Superseded by ADR-293 — its D1-D2 are D25-D26 there Date: September 26, 2026 Target Version: Nikaia 0.0.210 Answers: #208’s collect() into a declared map passes the checker and fails in rustc, with the owner’s choice: collect builds what the target declares Related: ADR-105 (Seq, and collect as its eager walk), ADR-152 D4 and ADR-207 D2 (a use answers a literal), ADR-223 and ADR-224 (text positions)

1. Context

let m: collections::HashMap[String, i64] = text.lines().map(fn(l) { (l, 1) }).collect()

passed the checker and failed in rustc: the emitter wrote .collect::<Vec<_>>() into a map. The ledger says Seq::collect hands back Vec[$T], so the checker should have refused the let, but the items were not typed (ADR-225) and a Vec of unknowns fit. With the items typed, the program was refused, which is a wall. The owner chose the other answer: build the map.

2. Decisions

D1 — collect() builds a list, or what the let, field or result it goes into declares.

Where nothing declares anything, collect() builds a Vec, as before. Where a let, a struct field or a function’s result declares a map whose key and value the items fit as pairs, a set whose element they fit, or String from characters or pieces of text, that is what it builds, and the value has that type. It is the same move the checker already makes for a literal: the place it is used says what it is.

Below, the language’s own collect builds the type the place declares, so the emitter leaves off the ::<Vec<_>> it writes everywhere else. Nothing is built twice: there is no list in between.

What the items do not fit is refused as before (NK1103): pairs are not a set of text.

D2 — Into a map whose key or value is text both kinds flow into, each is handed over as it is.

A map is collected from pairs, and its key and its value are two positions (ADR-223 D1). Where one of them is mixed, the pairs go through either_keys(), either_values() or either_pairs() before collect, as a list’s items go through either_items() (ADR-224 D3).

For that to be decided, the pass that decides tiers reads what map makes as what its lambda hands back, with the lambda’s parameter bound to what came in: lines.map(fn(l) { (l, 1) }) is pairs keyed by views. filter, rev, skip, take and step_by hand on what they were given. A number, a truth value and null are no text of either kind; they used to count as text of its own, which made a pair of a view and a number mixed.

3. What is not built

4. Consequences

#208’s entry closes. Found on the way and recorded there: a filter lambda that compares its item to a value fails in rustc (&char against char), with or without this change.

5. What is built

All of it, in 0.0.210: Checker::collect_by_use and Checked::collected_into; the emitter’s collect without the turbofish there; EitherPairs in nikaia_std::either_text, in the prelude; the pair hands, map’s lambda and the non-text literals in crates/nikaia/src/text_tiers.rs. crates/nikaia/tests/collect_into.rs runs a map, a set, an ordered set, text and a list, and a map both kinds of key are collected into and a result declares, at both settings of user_parallelism, and holds the refusal.

This site is open source. Improve this page.