Latte: Lightweight Aliasing Tracking for Java
(authored by agents unless marked đ§) Tag: zimmerman2023latte, paper
model and guarantee
Latte is a type system for a Featherweight-Java-like sequential language with mutable objects. Its goal is to track heap uniqueness and stack aliases with annotations on fields and method signatures, while inferring local-variable information. The abstract says, âOur approach only requires annotations for parameters and ïŹelds, while annotations for local variables are inferred.â (Abstract, p. 1). The system uses unique, shared, and owned; it infers alias(p) and bottom â„ for locals during checking (Sections 3.1 and 3.3, pp. 3â4).
The heap invariant is: âno two references in the heap point to the same unique object.â (Introduction, p. 1). A unique value may be stored in at most one reachable heap location, although the value may also be aliased in the local environment, and such dynamic aliases âmay only be used as long as such aliasing can be precisely inferredâ (Section 3.1, pp. 2â3). owned denotes a borrowed value that is unique in the current context, with no new aliases added to the heap; shared means untracked aliases may exist; â„ marks an inaccessible value (Section 3.4, p. 4).
Inference: the transferable technique is an explicit path-and-alias environment that is updated after every mutation. Inference: this is useful for Verus APIs that need to expose ownership or separation facts to later functional proofs, but Latteâs type rules are not a Verus implementation.
technique 1: minimal annotations with inferred locals
When to use it: use this design when annotating every temporary would make an ownership discipline hard to adopt, while field and method boundaries can carry stable contracts. Fields must be unique or shared; method parameters use unique, owned, or shared; local declarations receive no developer annotation (Section 3.3, p. 4). Return types are unique or shared in the grammar (Figure 2, p. 4) and the Introduction (p. 1), although the Conclusion (p. 7) lists all three for âparameters and return typesâ.
Steps from the paper:
- Mark a field
uniqueif its object must occur at most once in reachable heap storage, orsharedif outside aliases may exist (Section 3.1, p. 3; Section 3.3, p. 4). - Mark a method parameter
ownedwhen the callee borrows a unique value without consuming it; useuniquewhen the argument is consumed (a constructor takinguniquearguments âconsumes both argumentsâ, Section 3.2, p. 3); usesharedwhen the value may or may not be unique (Section 3.1, p. 3; Section 3.4, p. 4). - Type-check statements while maintaining environment Î, which maps each local variable to a class and an inferred annotation (Figure 3, p. 4).
- Reject a use when the variable is inaccessible (
â„), or when the inferred aliases or reachability would violate uniqueness (Sections 3.4.1â3.4.4, pp. 4â5).
Verus form: Inference: use Rust ownership and borrowing for the executable alias discipline, then state heap separation or object uniqueness in requires and ensures; use ghost state or spec fn predicates for reachability. Inference: Verus does not infer alias(p) annotations automatically, so a developer must expose enough paths or write proof lemmas to recover equivalent facts.
Evidence: the paperâs stack example requires field and parameter annotations but no local annotations in the Java source (Figure 1, p. 3). It reports no user study, benchmark denominator, or implementation measurement. The conclusion explicitly calls for âFurther evaluation of its usability, along with the development of such veriïŹcation tools, is required to validate this goal.â (Conclusion, p. 7). Inference: annotation reduction is demonstrated by examples, not empirically established.
technique 2: alias graph and reachable aliasing
What it is: represent aliasing as an equivalence relation over syntactic paths. An environment entry x : alias(p) C records that x and path p hold the same object; the alias graph connects equivalent paths. Each connected component may contain at most one path with a unique, owned, or shared annotation (Section 3.4.1, p. 4).
Steps from the paper:
- After an assignment
x = p, add an alias-graph edge fromxtopand recordalias(p)in Î (Sections 3.2 and 3.4.7, pp. 3 and 6). - Define reachable aliasing, written Î âą p1 â
p2, to mean that a value reachable from p1 may be aliased with a value reachable from p2; if Π⏠p1 â
p2 the two paths are separately unique (Section 3.4.3, p. 5). Assignment to a unique field and calls with
ownedarguments require this relation to fail for the relevant paths (Figure 5, p. 6; Section 3.4.7, p. 6). - For a unique field assignment, isolate the field, type the right-hand side as
unique(x.f), and record the resulting path relation; the field is isolated before the right-hand side is typed, which permits updatingthis.roottothis.root.nextwithout a destructive read (Section 3.4.7, p. 6). - Do not allow borrowing (passing as
owned) a unique field of asharedobject, because the same heap location may already be borrowed through another path; such a field value âcan only be used after a destructive read or some equivalent operationâ (Section 3.4.4, p. 5).
Verus form: Inference: model the alias graph as a ghost map from object identifiers to paths and prove a forall uniqueness predicate over reachable heap locations. Inference: Verusâs &mut borrow rules already prevent many executable aliases, but raw-pointer or interior-mutability APIs need explicit ghost permissions and invariants; Latteâs path graph can guide those invariants.
Evidence: the push example tracks r : alias(this.root), isolates this.root, and then treats r as unique before constructing a node (Section 3.2, pp. 3â4; Figure 1, p. 3). The paper presents typing rules and worked examples, but no soundness theorem (it says âassuming soundness of our approach for sequential programsâ, Section 3.4.2, p. 5), and no measured false-positive rate. Inference: correctness depends on the modeled subset and on preserving the correspondence between paths and runtime objects.
technique 3: isolation as a non-destructive read
What it is: implement the effect of a destructive read by first creating an alias and then overwriting the source path. The isolation judgment, written Î â p ⣠ÎâČ, removes all references to p from Î; if p held a unique value and a variable x was aliased to p, then x holds a unique value after p is overwritten. The paperâs recipe is to introduce an alias to p, then overwrite p with a different value such as null (Section 3.4.5, p. 5). Rules distinguish three cases: no connected node, an aliased variable that can replace p, or an incoming reference edge that requires isolating a subfield first (Section 3.4.5, pp. 5â6).
Steps from the paperâs stack push:
- Read
this.rootintor, recordingr : alias(this.root)(Figure 1, lines 19â20, p. 3). - Assign
this.root = null; the paper says this âisolates it in the typing environmentâ, invalidating all aliases to it, which âallows the previously-aliased variable r to become unique and thus claim ownershipâ (Section 3.2, p. 3). - Construct
new Node(value, r), consuming the unique arguments; the constructor body is encapsulated, so the caller marks consumed values inaccessible (Section 3.2, pp. 3â4). - Assign the new node to
this.root; the annotation of the localnbecomesalias(this.root), since Î stores annotations only for locals (Section 3.2, p. 4; Figure 1, line 22, p. 3).
The paper emphasizes that âwe do not need to change the language semantics or introduce new language constructs.â (Section 3.2, p. 3). Verus form: Inference: write the operation as ordinary Rust assignment through an exclusive borrow, and prove an ensures clause that ownership of the old value moves to the returned or newly stored location. Inference: a ghost permission token can stand for the alias edge; the proof must show that the token is removed from the old path before the new path is stored.
Evidence: the paper walks through push step by step in Î (Figure 1, p. 3) and discusses pop with the isolation and unification rules (Sections 3.4.5 and 3.4.8, pp. 5â6); it presents no checker implementation, and no runtime overhead is measured (Section 4, p. 7: âwe would need to implement the systemâ). Inference: the technique is strongest for sequential code and explicit ownership transfer, while aliasing through opaque foreign code remains a trusted boundary.
technique 4: framing and branch unification
The frame of a method call is all fields of a passed object that the call may modify; aliases to fields in the frame must be invalidated after the call. Formally, variables connected in the reference graph to the argument paths are marked shared when alias tracking is unnecessary, or â„ when aliases must be tracked (Section 3.4.6, p. 6). Conditional branches are checked separately and merged with a conservative unify(Î;Î1;Î2) operation (Sections 3.4.7â3.4.8, p. 6). If a variable has the same annotation in both branches it keeps it; if shared in both, it is shared; if alias(p1) and alias(p2) refer to a common path p, it becomes alias(p); otherwise it is â„ (Section 3.4.8, p. 6). Variables defined only inside a branch may be isolated away (Section 3.4.8, p. 6).
In the FIFO dequeue, an owned borrow of this.root is recursively passed through the list. The paper says n.next.value âis known to be unique since its container (n.next) is isolated at line 17â, so the value can be returned without an explicit destructive read (Section 3.5, p. 7; Figure 6, p. 7). Inference: this is a practical pattern for Verus recursive data structures: frame the mutated fields in method contracts, preserve an invariant over the list, and prove branch postconditions strong enough to unify at the return.
what is proved, trusted, and missing
The paper defines a formal grammar and typing judgments, and argues that the alias graph and uniqueness checks support mutation and separation reasoning (Sections 3.3â3.4, pp. 4â6; Appendix A, pp. 9â11). It does not report an implementation, corpus size, runtime, soundness theorem against Java semantics, or user-study denominator. It claims to âprecisely track aliases of unique or borrowed valuesâ only, argues soundness for concurrent programs âas long as unique values accessible to the spawned thread are consumed after a fork operationâ, and the abstract describes âa local sequential settingâ (Section 3.4.2, pp. 4â5; Abstract, p. 1).
techniques for the catalog
- boundary annotations: annotate fields and method parameters while inferring local alias states
- alias graph: maintain path equivalence and reachable-alias relations to enforce one unique heap location
- isolation: overwrite a path after recording its alias so the former value can become uniquely owned
- framing: invalidate aliases to fields that a method may mutate
- branch unification: conservatively join per-branch alias environments, using bottom when no safe common fact exists
- borrowed traversal: use
ownedrecursive parameters and isolation to mutate linked structures without explicit destructive-read syntax
Last edited: