?. Lends Its Receiver Where That Needs No Representation, And The Third Case Waits On The TetherStatus: Superseded by ADR-278 — its D1-D2 are D18, its D3 is part of D19 there
Date: September 22, 2026
Target Version: Nikaia 0.0.140
Builds on: ADR-113, whose D1 and D3 this implements for every
case that does not need a state the compiler does not have
Related: ADR-052 D8 (the translated note, now narrowed),
ADR-066 D3 (the match a reached method lowers to),
ADR-008 (the tether), ADR-094 D4 (a let over a
place is a view of it — the same sentence one construct away)
ADR-113 D1 says ?. takes nothing, and
Part I 3.5 already writes it. The compiler did not do
it, and what a program heard instead was the language below’s:
error[E0382]: use of moved value: `user`
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| help: you can `clone` the value and consume it, but this might not be your
| desired behavior
Two hints naming things this language does not have — ADR-008 D5 says a copy is written by the program and never inserted — about a file nobody wrote (Part III C.1).
Reading the record against the code found that it is not one piece of work. D2 gives the reach two answers: a member that copies comes out copied, and a member that does not comes out as a view of the receiver. The second is the state Part I 6.6 calls Tethered, and it is not built — #196 is at least four change packages, of which the representation is the expensive half. So one third of this record sits behind the largest entry in that file, and two thirds sit behind nothing.
Measured rather than reasoned, because the line between them was not
obvious: lowering the third case as D2 asks makes user?.name a ref String?,
and user?.name ?? "nobody".to_owned() then has a view on one side of the ??
and an owned value on the other, with no fit and no way to make one that does
not insert a copy. The receiver is usually a temporary besides, so the view
dangles — which is precisely the refusal the tether analysis would own.
?. over a field the compiler knows to copy lends its receiver.x.as_ref().map(|it| it.a), with and_then where ADR-052 D6
flattens. user?.id reads user where it lies and user is usable on the next
line — ADR-113 D1, for the half of D2 that needs no
representation.
Only where the compiler knows. The checker records the reaches whose member
copies, by the rule the keeps column already uses; a field whose type it could
not work out, and a field that would come out as a view, are left exactly as
they lowered before this record. That is the direction that cannot break a
program that worked (C.4), and it is why the set is
of the certain cases rather than their complement.
?. over a method that changes nothing lends its scrutinee.match x.as_ref() { Some(it) => …, None => None }
(ADR-066 D3’s match, over a borrowed scrutinee).
This half needs no representation at all, and that is the whole reason it lands here: what comes out of a reached method is the call’s own result, not a view of the receiver, so nothing about it reaches the state that is missing.
Asked of the mutates column and only where every candidate for the name
agrees — NK1138’s own rule one construct over. A name this compiler cannot
resolve is claimed nothing about.
A ?. over a field that does not copy still takes its receiver, and
ADR-052 D8’s translated note stays for it alone, narrowed to say
so: ?. over a member that is not copied takes the value it reaches through.
Not refused, although a refusal is what stands where Tethered would
everywhere else in this compiler (NK2302, NK2303). The difference is what
exists: those refuse programs that were already refused below. This one would
refuse find(1)?.name ?? "nobody".to_owned(), which compiles and runs today —
and refusing a correct program is the one thing this compiler may never do
(C.4).
?. has stop moving their receiver, and the
most common of them — find(1)?.greet(…) — is the one the tests were already
written around.as_ref() in each of two lowerings.?. on the left of an assignment, which ADR-113 §4 already
leaves out and the language does not have.?? should join a view to an owned fallback. It is the question
the third case runs into first, and it belongs with the state rather than with
the operator.D1, D2 and D3, at 0.0.140. D4 is a sentence in a notes page.
Checked::copied_reaches and Checked::lent_reaches, filled where the
checker knows and read by the emitter’s two ?. lowerings — the way
ADR-028 hands the emitter every answer it has no types for.diagnostics, narrowed to the one case that still moves.crates/nikaia/tests/nullable.rs: the two shapes run with the receiver
used twice, the unresolved reach is shown to lower as it did, and the third
case is pinned as a lowering rather than as a refusal — so the day the tether
lands, the test that has to change says so.