Atoms
Polonius defines the following atoms. To Polonius, these are opaque identifiers that identify particular things within the input program (literally they are newtype'd integers). Their meaning and relationships come entirely from the input relations.
Example
We'll use this snippet of Rust code to illustrate the various kinds of atoms that can exist.
#![allow(unused)] fn main() { let x = (vec![22], vec![44]); let y = &x.1; let z = x.0; drop(y); }
Variables
A variable represents a user variable defined by the Rust source
code. In our snippet, x
, y
, and z
are variables. Other kinds of
variables include parameters.
Path
A path indicates a path through memory to a memory location -- these roughly correspond to places in MIR, although we only support a subset of the full places (that is, every MIR place maps to a Path, but sometimes a single Path maps back to multiple MIR places).
Each path begins with a variable (e.g., x
) but can be extended with
fields (e.g., x.1
), with an "index" (e.g., x[]
) or with a deref *x
.
Note that the index paths (x[]
) don't track the actual index that was
accessed, since the borrow check treats all indices as equivalent.
The grammar for paths would thus look something like this:
Path = Variable
| Path "." Field // field access
| Path "[" "]" // index
| "*" Path
Each path has a distinct atom associated with it. So there would be an
atom P1 for the path x
and another atom P2 for the path x.0
.
These atoms are related to one another through the path_parent
relation.
Node
Nodes are, well, nodes in the control-flow graph. They are related
to one another by the cfg_edge
relation.
For each statement (resp. terminator) S in the MIR, there are actually two associated nodes. One represents the "start" of S -- before S has begun executing -- the other is called the "mid node" -- which represents the point where S "takes effect". Each start node has exactly one successor, the mid node.
Loans
A loan represents some borrow that occurs in the source. Each
loan has an associated path that was borrowed along with a mutability.
So, in our example, there would be a single loan, for the &x.1
expression.
Origins
An origin is what it typically called in Rust a lifetime. In Polonius, an origin refers to the set of loans from which a reference may have been created.