ADR-228: A ?. View Out of a Temporary Is Held for the Rest of the Block

Status: Superseded by ADR-278 — its D1-D2 are D21-D22 there Date: September 26, 2026 Target Version: Nikaia 0.0.211 Answers: #192, a ?. whose receiver is a temporary still takes it, with ADR-191 D3’s what it needs is a lowering and not a state Refines: ADR-113 D1 (?. takes nothing), for the one shape ADR-189 and ADR-191 left Related: ADR-185 D2 (a binding written for the language below), ADR-107 D3 (nothing inserted that copies)

1. Context

#192 described the temporary shape as one that takes its receiver, which is harmless: a temporary has no next line. Probing found every shape that takes compiling and running - find(1)?.name, find(1)?.home?.x, find(1)?.tags?.len() - and one that did not:

impl User { fn label(ref self) -> ref String { return self.name } }
let a = find(1)?.label() ?? "none"     // rustc: temporary value dropped while borrowed

A reached method that hands back a view hands back a view of the User find(1) made, and that value ends at the ;. Part III C.1.

2. Decisions

D1 — The receiver is bound first, and the reach reads the binding.

Where the checker finds a lent ?. method reach whose result is a view and whose receiver is rooted in a call, the emitter writes the receiver into a binding of its own on the line before the statement and the reach reads it:

let __nikaia_held_0 = find(1);
let a = nikaia_std::index::or(match __nikaia_held_0.as_ref() { … }, || "none");

The value lives to the end of the block, as a name the program bound would. Nothing is copied, and nothing runs that did not run: the call ran first in that statement anyway.

D2 — Only where binding it first changes nothing about what runs.

Not on the lazy side of ??, && or ||, where it may not run at all; not in a match arm; not after another call in the same statement, which it would overtake; and not where the view is the block’s value or the function’s result, which would outlive the binding. There the program is refused in this language’s words, naming the let the program can write. That is ADR-191 D3’s deciding where a hoist is safe, answered by where the call would have run.

3. What is not built

A hold on the lazy side, which would need the binding filled only when that side runs; the refusal names the one-line way out.

4. What is built

All of it, in 0.0.211: Checked::held_reaches, Emitter::hold_temporaries and Emitter::held_in. crates/nikaia/tests/nullable.rs runs the program from §1 with a view held for a let and one kept past it, and holds the refusal on the lazy side of ??.

This site is open source. Improve this page.