Status: Accepted Related: ADR-024 (the type checker says only what is written down — D1 is that discipline failing in one direction, not an exception to it), ADR-288 (a signature naming its receiver’s type arguments, which is what makes D2 answer with what this container holds), ADR-288 D11 (why D2 takes one step and not a chain), ADR-312 D1 (the rule that needed this before it could be written).
Two rules in one place, and neither is about sharing, though a shared value lent out without unwrapping it depends on both.
A view of a generic type has to answer something. If ref Vec[i64],
ref HashMap[String, Stats] or ref Shared[Connection] came out as “nothing
is known”, the checker would say nothing, the program would be emitted, and a
mismatch would be reported by rustc, about the generated file — the one
thing Part III C.1 forbids. That would not be a gap in what the checker
knows — the type is right there — but a step that throws it away.
A transparent container has to be accepted. Part III says of fs::Mapped
that “a parser cannot tell the difference”, and std’s ledger spells it out
with a fs::Mapped::deref entry. A function taking a text view that refused a
mapped file would break what the specification promises about the type.
The two point in opposite directions: one lets too much through, the other too little.
Changed by ADR-184 D1 and D2: a view is spelled ref X, and the text view is written ref String — str is not a name a program, signature or message uses.
ref Vec[i64] is a view of a Vec[i64]. Three cases and nothing else:
ref ref String is not a type this language has;String is the text view, the one rewrite;A tuple and a lambda answer nothing, deliberately: a tuple of views is not a view of a tuple, and nothing writes down what a view of a lambda would be.
deref is seen through, once, and only to rescue a comparison that has already failed.A container that records Type::deref is one a caller is not meant to notice. So
where a found type does not fit what is wanted, and the ledger says the found type
derefs, the question is asked again of what the deref gives.
Only as a rescue. It runs after a direct comparison has failed, so seeing through a container can turn a refusal into an acceptance and can never turn an acceptance into a refusal. That is what makes it safe to add to a checker whose whole discipline is to say nothing where it knows nothing (ADR-024): this says more only where it was already about to refuse.
One step. A container inside a container is two questions, and this record
answers the first. The second - reaching through a Shared into what the value
it shares holds - is not decided here.
The receiver’s own arguments bind the signature’s variables as they do for any
other method (ADR-288), so an entry written
[T](self: ref Shared[T]) -> ref(self) T answers with what this container holds rather than with a variable. That is what
makes D2 enough for a generic container and not only for Mapped.
A program rustc would refuse is refused by Nikaia — a text view handed a
ref Vec[i64] is NK1102, in this compiler’s words and with a help line.
A function taking a text view accepts a mapped file, as the specification promises.
ADR-312 D1 rests on this. A handle on a shared value is
duplicated where it is handed on; lending one out is the case where nothing is
handed on at all, and D1 and D2 are the rule under which serve(ref db) means
something.
Shared[T] is seen through by D2 because std’s ledger records a
Shared::deref, with no further decision — the shared case is a consequence of
this record rather than a special case beside it. SharedMut[T] records no
deref — there is no view straight through a lock, so it is opened through its
doors (ADR-281).