Lectures onType Theory
ch:ownership-borrowing: ch:ownership-borrowing
appendix sectionsolutions

ch:ownership-borrowing: ch:ownership-borrowing

exercise 46.1.

The complete state trace is commandLb’s stateinitialϵO(A)beginSαbαS{α}(A)beginSβbαβS{α,β}(A)readbαβS{α,β}(A)endSβbαS{α}(A)readbαS{α}(A)endSαbϵO(A). The steps use Share-begin, Share-nest, Read, Share-end, Read, and Share-return, in that order. Freshness holds because αβ, and each end command names the top lifetime.

exercise 46.2.

Use Ex-begin at fresh α, Ex-reborrow at fresh β, Write with any closed v:A, Ex-pop at β, and Ex-return at α. This derives (ϵ,O(A))(α,Xα(A))(αβ,Xαβ(A))(αβ,Xαβ(A))(α,Xα(A))(ϵ,O(A)). No sharing rule has an exclusive state in its premise. Ending α while β is active matches neither Ex-pop, whose conclusion must remove the top suffix β, nor Ex-return, whose premise has a singleton exclusive stack.

exercise 46.3.

With fresh k, Move concludes L;Ω,h:O(A)move h as kL;Ω,h:D,k:O(A). Inverting Read and Write requires the named state to belong to their displayed live-state sets; D belongs to neither. Inverting Drop requires h:O(A), also absent. The destination has exactly that owned state, so Read applies to k.

exercise 46.4.

Activating [b:σ]Sn gives the borrow a kind at region level n. Returning that borrow would therefore require both Lnkind(τ) and the Region premise kind(τ)Ln1. The stratified kind order does not have LnLn1, so the premises cannot be solved. A closure containing the borrow has a kind at least as restrictive as the captured binding; it produces the same incompatible inequalities. The argument uses the Affe kind level, not lexical scope inspection of result syntax.

exercise 46.5.

First take Γ=a:ArrayA, with a unique and consumed by the update. There is no other root for the array, so overwriting its representation is observationally equivalent to the pure replacement. Second take Γ=a:ArrayA,b:ArrayA, allow a and b to denote the same array, consume a, and leave b unused. The path is affine because neither handle is used twice. It does not establish absence of the alias b; a surrounding context or later lazy evaluation could still observe that value. In-place replacement needs the first environment’s uniqueness fact, not only a use count.

exercise 46.6.

Borrow m:Mutαa at β to obtain m:Mutαβaβ:Lendβ(Mutαa). Ending β consumes Nowβ and returns the persistent evidence eβ:Endβ. Reclamation consumes the linear lender β, uses eβ, and recovers m. Ending α similarly consumes Nowα. The outer reclamation consumes the outer linear lender and uses Endα to recover the original owner. The two mutable borrowers have already been consumed by their respective scope computations, so no borrower survives either reclamation.

exercise 46.7.

Denotational strong confluence and leak freedom of a safe final mutative configuration are proved. Progress of safe mutative configurations is conjectured. Preservation of safety and behavior uniqueness are conditional on the association-bisimulation conjecture; the latter also uses the proved denotational diamond. Strong confluence of the mutative semantics is unsupported: neither the published theorem nor the stated conditional corollary has that conclusion.

exercise 46.8.

The observer can see every deque empty after the delayed worker has removed a task but before it publishes the two children. An emptiness test then reports termination although two tasks will shortly become available. With an outstanding-task counter, removing the parent does not make the count zero: the parent remains outstanding until publication accounts for its children, so the observer cannot finish during the gap. The repair does not prove that the core borrowing API is pure, and it does not establish the association bisimulation conjecture.

exercise 46.9.

Let the initial states be b1:O(A),b2:O(B). The command sequence beginSαb1;beginSβb1;move b2 as k;endSβb1;endSαb1;beginXγb1;endXγb1;drop b1. produces lifetime stacks ϵ,α,αβ,αβ,α,ϵ,γ,ϵ,ϵ. The states of b1 are respectively O,S{α},S{α,β},S{α,β},S{α},O,Xγ,O,D; b2 changes from O(B) to D at the move and fresh k receives O(B). The runtime makes exactly the same mode changes and moves the B-payload, so agreement holds after each command. Replacing endSβb1 by endSαb1 fails because α is not the top lifetime.

exercise 46.10.

Without destination freshness, move into an existing owned k has two candidate payloads for one target entry; the unique-result clause of lemma 46.4 fails. Without the top condition, ending the outer lifetime of Xαβ(A) can leave a runtime inner view whose static stack no longer has its enclosing scope, breaking agreement and the final no-dangling argument. Without Affe’s result-kind premise, {|&Sx|}x,Sn may return the region-level borrow; the owner can then resume while the escaped borrow remains reachable, so the source containment step used in the nonescape argument fails.

exercise 46.11.

Suppose MAD and MmM. The forward half of the conjectured bisimulation supplies D with DdD and MAD. The last judgment is the definition of safety for M, so safety is preserved conditionally.

For behavior uniqueness, mere existence of associations permits one mutative state to associate with unrelated denotational states, or two mutative outcomes to associate with one state without being equal. The diamond joins denotational reductions only. Bisimulation is needed to transport each mutative execution into that diagram and transport the joined observations back; the result remains conditional because that bisimulation is conjectural.

exercise 46.12.

One possible five-row separation is invariantrepresentative judgmentaffine usea:Ae:B with no contraction on auniquenessΓa:AownershipΩ(a)=O(A)exclusive borrowΩ(a)=Xα¯β(A)separationσ,havR. Affine use separates a one-use program from one that duplicates a. Uniqueness separates an in-place pure update from the same update with a live alias. Ownership separates transfer/drop authority from a read-only handle. An exclusive borrow separates mutation through the top view from an attempted simultaneous shared view. The points-to assertion separates a command with the owned heap cell in its footprint from a command whose precondition lacks that cell. These judgments are not translations of one another.

exercise 47.1.

The sharing let has nodes c=C and p=P(c,c), rooted at p. Counting the root edge, p has one incoming reference and c has two. The copied expression has c1=C, c2=C, and p=P(c1,c2). Each of the three nodes has one incoming reference. Node renaming cannot turn one two-referenced node into two nodes, so the rooted graphs are not isomorphic.

exercise 47.2.

Give a type δ. The C-equation gives α=δ and the bound root type Tδ. The two argument positions of P give β=Tδ twice; the sharing interface is the equation equating the type of each occurrence of x with that single bound-root type. The result is U(Tδ). Up to renaming δ, this solution is most general.

exercise 47.3.

Correcting a unique list of unique elements changes only the outer spine attribute, giving a shared list whose element attribute remains unique. Such a type need not be the result of any constructor scheme; it is the temporary shared view used at contraction. Correcting a unique list of already shared elements likewise changes only the spine and leaves the elements shared.

exercise 47.4.

Type C(a) at σ, bind x:σ, and present the body first with two variables y:[σ],z:[σ]. The P-scheme types P(y,z); Contr substitutes x for both variables, and Share joins the binding. In the denotation, the C-root has two incoming P-edges, so definition 47.10 checks its corrected type. Assigning both edges the uncorrected unique type would assert one incoming reference while displaying two.

exercise 47.5.

For a unique spine and shared elements take b=u, a=m. The scheme condition is the allowed edge um. For a shared spine and unique elements it becomes mu, the unique forbidden edge. Reflexive-transitive closure therefore accepts the first problem and rejects the second.

exercise 47.6.

Consume the cells headed by 3,1,4,2 in order. Once the pivot cell is removed, the tail reference is the sole incoming reference to the next spine cell. Start with empty accumulators. Relink the 1-cell onto the low accumulator, the 4-cell onto the high accumulator, and the 2-cell onto the low accumulator. The accumulators are then 2::1::[] and 4::[]; reversing the low accumulator gives 1::2::[]. Each relink has one incoming spine reference and retains a tail edge at the list-tail type. With a shared input spine, the first matched cell already lacks the unique outer attribute, so condition 2 of definition 47.18 blocks the first relink.

exercise 47.7.

Let η send each pattern-interface node to its matched host node. Rule typing gives the same attributed root type on the left and right interfaces under η. For an interface node whose reference count remains one, its original local inequality is unchanged. If the right side introduces a second reference, its rule derivation uses contraction, so both outgoing positions demand [TG(n)]. Internal replacement equations are typed by the right-side rule derivation; host equations are unchanged. Reconstructing a source expression may choose different lets or a different presentation of a cycle, so completeness yields an expression with the same graph denotation as the parser’s reduct, not necessarily the same syntax.

exercise 47.8.

Enumerate first-order instances of the principal conventional solution in increasing substitution size. For each instance, generate the finite attribute graph, compute its transitive closure, and report the symbolic attribution exactly when the forbidden edge is absent. Exact conventional generation proves the first phase sound; lemma 47.15 and theorem 47.16 prove every reported attribution sound. The conventional principal theorem factors known typings through one solution, but it supplies neither a finite bound on instances nor a decision that no attributable instance exists. Unrestricted enumeration is therefore only semidecidable.

exercise 48.1.

x overlaps each of x.0,x.1,x.0.1, with x the shorter prefix. x.0 overlaps x.0.1, with x.0 the shorter prefix. x.0 is separated from x.1, and x.1 is separated from x.0.1. These are all six unordered pairs.

exercise 48.2.

After moving x.0.1, the overlapping paths x, x.0, and x.0.1 are unreadable. The separated siblings x.0.0 and x.1 remain readable. Assigning a fresh box to x.0.1 removes the only partial marker, so all five listed paths are readable again.

exercise 48.3.

At block exit the local binding y is removed, so the ordinary output environment can be empty and hence vacuously well formed. The result type is nevertheless &y. Adding fresh γ:&y makes well-formedness inspect that borrow; its referent is absent after the block, so the judgment fails.

exercise 48.4.

For τ1, the dependency graph is xyz. One ranking is ϕ(x)=2,ϕ(y)=1,ϕ(z)=0. For τ2, the graph contains xyx, so the inequalities would require both ϕ(x)>ϕ(y) and ϕ(y)>ϕ(x). Lookup beginning at x follows the borrow to y, then the borrow back to x; the obligation rooted at x repeats.

exercise 48.5.

The whole place x overlaps both loans. Its shared use conflicts with the unique x.1-loan; its unique use conflicts with both. At x.0, a shared use is permitted because the only overlapping loan is shared, while a unique use is rejected. At x.1, both shared and unique uses conflict with the overlapping unique loan.

exercise 48.6.

With empty Θ, r occurs in no stored type, so collection replaces its loan set by . When Θ contains a component type mentioning r, collection retains {uniq x}. Tuple construction needs the latter result: the already evaluated first component still holds the unique borrow, so the attempted second unique borrow must be rejected.

exercise 48.7.

For move, safe abstraction locates a uniquely owned value; runtime destructive read writes undefined and typing strikes the same owner type. For mutable borrow, ownership safety establishes absence of an overlapping loan before the runtime creates a location value; the anonymous result binding records its referent. For block exit, runtime recursively drops the latest frame and typing removes the same lexical bindings; borrow invariance rules out a returned reference to any removed local. None of these frozen-core cases has a projection rule, so they do not prove the named-field extension.

exercise 48.8.

Type the first sequence component from Γ to Γ1. The second component is typed from gc-loansΘ(Γ1), not directly from Γ1. A reduction inside the first component preserves the same continuation Θ, so a region mentioned by an already evaluated component cannot be cleared. Oxide’s value-preservation-under-drop/collection lemma re-establishes the typing of those temporaries after collection. Apply the induction hypothesis to the stepping component, then rebuild the sequence rule with the preserved Θ, rewritten result type, and residual output union.

Search the book

Type to search the local edition.