ADR-113: ?. Reaches Through a View, and the Receiver Stays Usable

Status: Superseded by ADR-278 — its D1-D4 are D16, D17, D18 and D23 there Date: September 16, 2026 Target Version: Nikaia 0.0.8 Related: ADR-052 D6 and D8 (?. over a field, and what it took), ADR-066 D3 (?. over a method, and its match), ADR-094 D4 (a let over a place is a view of it), ADR-107 D1 and D3 (a value’s state is the compiler’s per use; a copy is written or refused, never inserted), ADR-008 (a view and the buffer that owns it), Part I 3.5 and 6.6

1. Context

let name = user?.name followed by println(user) was refused in the language below with use of moved value, and the specification called that a rule: ?. takes the value it reaches through. The rule came from the lowering — Option::map takes its receiver by value — and the record that named it translated rustc’s note and dropped the three hints that named .as_ref() and .clone(), because the language has neither.

That is the shape docs/language-review.md §1.1 found under the & at every call: a Stage-0 choice became a sentence in Part I, and the message was translated instead of the cause. In every language that has ?. the operator reads through its receiver and leaves it where it was. And since ADR-094 D4 and ADR-107 this language has the rule that decides such a case for everything else: whether a value is a view or owned is the compiler’s, per use, and a copy is something a program writes.

2. Decisions

D1 — ?. takes nothing. It reaches through a view of its receiver.

user?.name reads user where it lies. user is usable on the next line, in a println, in a second ?., in a call. There is no move and no message about one.

D2 — What comes out is a T? whose state is the compiler’s, as everywhere.

Where the reached member copies — a number, a bool, a char — the result is a copy. Where it does not, the result is a view tethered to the receiver, kept alive by the rules Part I 6.6 and ADR-008 already apply to any view of a place. A program that wants to keep the result past its receiver writes .to_owned(), which is ADR-107 D3’s rule for text applied to what ?. reaches. Nothing is copied that the program did not write.

D3 — The lowering follows: as_ref() before the map, a borrowed scrutinee before the match.

x?.a is x.as_ref().map(|it| &it.a) — with the copy where D2 says copy — and ADR-066 D3’s match for a method takes x.as_ref() as its scrutinee. The flattening of ADR-052 D6 (map against and_then) is unchanged; it only reads through a reference now.

D4 — There is no longer a move to translate.

ADR-052 D8’s translation of “Option::<T>::map takes ownership of the receiver” goes with the move it explained. A receiver used again after a ?. is an ordinary program, and the checker says nothing.

3. Consequences

4. What this does not decide

5. What is built

Nothing. x?.a lowers to x.map(|it| it.a), a method reach to a match over x by value, and a receiver used again is refused below with the translated note. The order of work:

  1. the two lowerings over as_ref(), with the copy where the member copies;
  2. the tether analysis treating the result of ?. as a view of the receiver where it is one;
  3. the translation of D8’s note removed, and a test that uses the receiver again in crates/nikaia/tests/.

#192 carries it.

This site is open source. Improve this page.