---
# System prepended metadata

title: Purely forward propagation

---

# Purely forward propagation

## Intuition

* A *loan* is a reference to a place in memory and the conditions it was borrowed (shared, mutable)
* An *origin* is a set of loans {L}, such that if a reference has origin O, then we know that:
    * invaliding one of the loans in {L} may invalidate the reference
    * actions that do not invalidate any of the loans in {L} cannot invalidate the reference
* When we have an access that invalidate some loan L:
    * We mark any origins that contain L at that point as invalidated
* Questions Niko is not sure about
    * Do we still have to "propagate" subset etc?
    * What's the best way to think about that :) 

## Tentative idea

### State we compute

* `subset(O1, O2, N)` -- `O1 <= O2` must hold on entry to the node `N`
* `loan_in_origin(L, O1, N)` -- the origin `O` contains the loan `L` on entry to the node `N`
* `origin_invalidated(O, N)` -- data with origin `O` is invalidated on entry to the node N

### End goal we are searching for

* `invalidated_origin_accessed(O, N)` -- origin `O` which is invalidated was accessed; error


## Rules

### Inputs

* `access(O, N)`: access data with origin `O`
* `invalidate_loan(L, N)`: invalidate the loan `L` at the node `N`
* `clear_loan(L, N)`: the path named in `L` changed without invalidating the underlying memory; subsequence invalidations of `L` do not affect existing references
* `clear_origin(O, N)`: all references with origin `O` was overwritten
* `introduce_loan(L, O, N)`: introduce the loan `L` into origin `O` at node `N`
    * Every borrow `&'a place` or `&'a mut place` introduces, for some unique origin `'a`:
        * one loan in `'a` for the borrow itself
        * various subset relationships between each origin `O` dereferenced by place and `'a`
* `introduce_subset(O1, O2, N)`: require that `O1 <= O2` at node `N`
* `cfg_edge(N1, N2)`: control-flow graph edge

Note the convention: Input facts are in the imperative mood ("invalidate loan") while computed facts use the past participle ("loan invalidated").

### Assumptions about ordering

For a given node `N`...

* First we perform any accesses `access(O, N)`
* Then we invalidate any loans `invalidate_loan(L, N)`
* Then we clear any loans or origins
* Then we introduce any loans, subsets, etc
* Then we remove things from scopes

This corresponds to 

```
place = expr
```

* Evaluating the expr accesses the origins (including potentially some in place)
* Then place is overwritten, invalidating and clearing loans
* Storing the value also creates subtyping relationships between the type of the value that was stored and the place it was stored into

### Computing subset

The `subset(O1, O2, N)` relation indicates that `O1 <= O2` on entry to node `N`

```
subset(O1, O2, N2) :- // Introduced by predecessor
  cfg_edge(N1, N2),
  introduce_subset(O1, O2, N1)

subset(O1, O2, N2) :- // Carried over from predecessor
  cfg_edge(N1, N2),
  subset(O1, O2, N1),
  !clear_origin(O1, N1),
  !clear_origin(O2, N1).

subset(O1, O3, N1) :- // Transitive closure
  subset(O1, O2, N1),
  subset(O2, O3, N1).
```

### Computing loans in an origin

The `loan_in_origin(L, O, N)` relation indicates that the origin `O` contains the node `L` on entry to node `N`

```
loan_in_origin(L, O, N2) :- // Introduced by predecessor
  cfg_edge(N1, N2),
  introduce_loan(L, O, N1)

loan_in_origin(L, O, N2) :- // Carried over from predecessor
  cfg_edge(N1, N2),
  loan_in_origin(L, O, N1),
  !clear_loan(L, N1),
  !clear_origin(O, N1),
  !invalidate_loan(L, N1).

loan_in_origin(L, O2, N) :- // Transitive closure
  subset(O1, O2, N),
  loan_in_origin(L, O1, N).
```

### Computing invalidated origins

An *origin* is invalidated if it contains some *loan* that has been invalidated. Invalidating a loan is an input fact, `loan_invalidated`, and it takes effect during a node's execution. So we look for origins that (a) contained a loan `L` on entry to some node `N` and (b) the node invalidated the loan `L`.

```
origin_invalidated(O, N2) :- // Introduced by predecessor
  cfg_edge(N1, N2),
  loan_in_origin(L, O, N1),
  invalidate_loan(L, N1).
```

### Error: access to invalidated origins

An error occurs when some node N tries to access data with origin O, but O is invalidated on entry to N.

```
invalidated_origin_accessed(O, N) :- // Introduced by predecessor
  access(O, N),
  origin_invalidated(O, N).
```

## Fact Generation

### Accesses
Any read (or write) of a place `P` counts as an access of
* any origin in the type of `P`. 
    * For example, using a `&'outer Vec<&'inner u32>` accesses both `'outer` and `'inner`.
* any origin that is dereferenced in `P`, or, more precisely, any origin in the type of any reference that is dereferenced in `P`. 
    * For example, reading from `(*x).0`, where `x: &'x0 (&'x1 u32, &'x2 u32)` accesses
        * `'x0` because of `*x`
        * `'x1` because of the `.0`, which gives the final type `&'x1 u32`

Mutably borrowing `P` counts as a write to `P` in this context, immutable borrows count as a read.
        
### Invalidation
If a read or write violates an existing borrow `'L`, then `'L` is invalidated.
* For example, reading `x` invalidates and mutable borrow `'L_mut_x` of `x`.

#### Questions
* Does borrowing `&'L_p mut p` always invalidate + clear `'L_p`, because `p` is written to (mutably borrowed), but the borrow is also re-created?
  **Answer:** Yes, because the invalidation happens conceptually *before* the clear and may be propagated across subsets.
* Should writing to `*y`, where `y = &'L_*x mut *x`, `x = &'L_p mut p`, `p: u32`, invalidate `'L_*x`, `'L_p`, or both? How do we know if `x` still references `p` at the time of the write?
**Answer:** usage of a path invalidates any origin whose associated path starts with the used path. So using `*y` invalidates **neither** `'L_*x` **nor** `'L_p`, but **does** invalidate any `'L_y`, `'L_*y` where they exist.
  ```rust
  let mut x = 42;
  let p = &mut x;
  let pp = &mut *p; // reborrow `p`
  
  // `p` is no longer used. How is `pp` (the reborrow) connected to `x`?
  
  x = 0;
  dbg!(pp);
  ```
    * I think we would need to propagate `access` across the subset graph as well? -Dylan
* How do we handle assignments that invalidate unrelated origins? Example `diamond-ref-mod` (Dylan):
  ```rust
  let mut x = 4;
  let mut p = &22;

  if maybe() {
      p = &x;
  } else {
      x = 0; // invalidate x
  }

  dbg!(p); // access p (or *p?)
  ```
    * Here, there can only ever be **either** a relationship between `p` and `x`, **or** a mutation of `x`, but not both. However, both the subset relationship and the invalidation from the write reach the access of `p`.
    * Current idea: only invalidate origins from which the invalidation is CFG-reachable.
  **Answer:** this is solved by removing the transitive closure on `origin_invalidated` and `subset` in favor of propagating `invalidate_origin` across subsets in the original node.
  This has, however, caused problems in `issue-47680`.
* How do we handle self-invalidation? Example `self-invalidation-loop` (Dylan):
  ```rust
  fn main() {
      let mut x = 42;
      let mut v: Vec<&mut i32> = vec![];

      while maybe() {
          let tmp = &mut x; // L_x
          v.push(tmp);
      }
  }
  ```
    * Here, the problem is that the lifetime of `tmp`'s `'L_x` on one iteration is **extended** into the next by storing it in `v`. This makes it not match lexical scopes anymore. However, when `tmp` is re-created, this clears `'L_x`, so neither additional subset relations nor invalidation are propagated.
    * Is this possible to solve without liveness (of `v` or `'tmp`)?
  **Answer:** this is also solved by intra-node propagation of `invalidate_origin` before any corresponding clears for that origin.

### Clearing Origins
Origins are cleared
* when they are created.
    * For example, taking a borrow `&'L_P P` of `P` clears `&'L_P`.
* when expressions in the path of a loan origin change, but its target and the associated memory don't.
    * Consider the following code
      ```rust
      let x = 42;
      let y = 22;
      let mut temp = &x;
      let p = &*temp; // &'L_*temp *temp == &x
      temp = &y; // now `*temp != x`, but `*p == x` and `x` still exists.
                 // Therefore, `p` and `'L_*temp` are not invalidated, but 
                 // future occurences of `*temp` are unrelated to `p`.
      ```

### Subset Relations
Relationships between origins arise from borrows and assignments.

#### Borrows
* **Immutably** borrowing `P = *Q` as `&'L_*Q *Q` where `Q` is a **shared** reference `Q: &'Q T` introduces `'L_*Q <= 'Q`, because the outer reference `'L_*Q` cannot outlive the inner reference `'Q`.
* **Immutably** borrowing `P = *Q` as `&'L_*Q *Q` where `Q` is a **mutable** reference `Q: &'Q mut T` introduces `'L_*Q <= 'Q` for the same reason, but continues recursively adding borrow subset relations for `Q` (i.e., if `Q = *R`, then consider origins in `R`).
    * This is not necessary for shared refs because they are `Copy`, while mutable refs mean the original source cannot be used while the new borrow is live.
* **Mutably** borrowing `P = *Q` as `&'L_*Q mut *Q` where `Q` is a **shared** reference `Q: &'Q T` is an error (mutable borrow of shared content).
* **Mutably** borrowing `P = *Q` as `&'L_*Q mut *Q` where `Q` is a **mutable** reference `Q: &'Q mut T` has the same borrow constraints as immutable borrows of mutable content (`'L_*Q <= 'Q` and adding constraints recursively).

#### Types
Assignments of values whose types include origins introduces subset constraints according to **variance**.

| Type                     | `'a`      | `T`           | `U`       |
| ------------------------ | --------- | ------------- | --------- |
| `&'a T` and `*const T`   | covariant | covariant     |           |
| `&'a mut T` and `*mut T` | covariant | invariant     |           |
| `Box<T>` and `Vec<T>`    |           | covariant     |           |
| `[Unsafe]Cell<T>`        |           | invariant     |           |
| `fn(T) -> U`             |           | contravariant | covariant |

For example, assigning `tmp = &'L_v mut v`, where `v: Vec<&'v mut u32>` and `tmp: &'tmp0 mut Vec<&'tmp1 mut u32>` introduces 
* `'L_v <= 'tmp0` because of covariance of the reference in `'a`
* `'v <= 'tmp1` **and** `'tmp1 <= 'v` because of invariance of the mutable reference in `T` (even though these are again lifetimes in a reference)

#### Bounds
Additional constraints may arise from `where` bounds.

## Examples

### Example A

```rust=
let mut x = 3;
let y: &u32 = &x;
x = 4;
drop(y);
```

#### Input relations

#### CFG

```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 
    
    Decls [ label = <<table border="0">
    <tr><td align="left">let x:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let y:</td>
        <td align="left">&amp;'y u32</td></tr>
    <tr><td align="left">L0:</td>
        <td align="left">shared(x)</td></tr>
    </table>> ]

    A [ label = <<table border="0">
    <tr><td>A: x = 3</td></tr>
    <tr><td>invalidate_loan(L0)</td></tr>
    </table>> ]

    B [ label = <<table border="0">
    <tr><td>B: y = &amp;'0 x</td></tr>
    <tr><td>introduce_loan(L0, '0)</td></tr>
    <tr><td>introduce_subset('0, 'y)</td></tr>
    </table>> ]
    A -> B

    C [ label = <<table border="0">
    <tr><td>C: x = 4</td></tr>
    <tr><td>invalidate_loan(L0)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'y)</td></tr>
    <tr><td>loan_in_origin(L0, '0)</td></tr>
    <tr><td>loan_in_origin(L0, 'y)</td></tr>
    </table>> ]
    B -> C

    D [ label = <<table border="0">
    <tr><td>D: drop(y)</td></tr>
    <tr><td>access('y)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'y)</td></tr>
    <tr><td>origin_invalidated('0)</td></tr>
    <tr><td>origin_invalidated('y)</td></tr>
    <tr><td>invalidated_origin_accessed('y)</td></tr>
    </table>> ]
    C -> D
}
```

### Example #47680

```rust
#![feature(nll)]

struct Thing;

impl Thing {
    fn maybe_next(&mut self) -> Option<&mut Self> { None }
}

fn main() {
    let mut temp = &mut Thing;

    loop {
        match temp.maybe_next() {
            Some(v) => { temp = v; }
            None => { }
        }
    }
}
```


```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 

    Decls [ label = <<table border="0">
    <tr><td align="left">let temp:</td>
        <td align="left">&amp;'temp mut Thing</td></tr>
    <tr><td align="left">let t0:</td>
        <td align="left">&amp;'t0 mut Thing</td></tr>
    <tr><td align="left">let v:</td>
        <td align="left">&amp;'v mut Thing</td></tr>
    <tr><td align="left">L_Thing:</td>
        <td align="left">mutable(Thing)</td></tr>
    <tr><td align="left">L_*temp:</td>
        <td align="left">mutable(*temp)</td></tr>
    </table>> ]

    A [ label = <<table border="0">
    <tr><td>temp = &amp;'0 mut Thing</td></tr>
    <tr><td>clear_loan(L_temp)</td></tr>
    <tr><td>introduce_loan(L_Thing, '0)</td></tr>
    <tr><td>introduce_subset('0, 'temp)</td></tr>
    <tr><td>-------------------</td></tr>
    </table>> ]

    B [ label = <<table border="0">
    <tr><td>t0 = &amp;'1 mut *temp</td></tr>
    <tr><td>clear_loan('t0)</td></tr>
    <tr><td>introduce_loan(L_*temp, '1)</td></tr>
    <tr><td>introduce_subset('temp, '1)</td></tr>
    <tr><td>introduce_subset('1, 't0)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'temp)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'temp)</td></tr>
    </table>> ]
    A -> B

    C [ label = <<table border="0">
    <tr><td>v = MaybeNext(t0)</td></tr>
    <tr><td>clear_origin('v)</td></tr>
    <tr><td>introduce_subset('t0, 'v)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'temp)</td></tr>
    <tr><td>subset('0, '1)</td></tr>
    <tr><td>subset('0, 't0)</td></tr>
    <tr><td>subset('temp, '1)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('1, 't0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'temp)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '1)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 't0)</td></tr>
    <tr><td>loan_in_origin(L_*temp, '1)</td></tr>
    <tr><td>loan_in_origin(L_*temp, 't0)</td></tr>
    </table>> ]
    B -> C

    D [ label = <<table border="0">
    <tr><td>temp = v</td></tr>
    <tr><td>clear_loan(L_*temp)</td></tr>
    <tr><td>clear_origin('temp)</td></tr>
    <tr><td>introduce_subset('v, 'temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'temp)</td></tr>
    <tr><td>subset('0, '1)</td></tr>
    <tr><td>subset('0, 't0)</td></tr>
    <tr><td>subset('0, 'v)</td></tr>
    <tr><td>subset('temp, '1)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('1, 't0)</td></tr>
    <tr><td>subset('1, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'temp)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '1)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 't0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'v)</td></tr>
    <tr><td>loan_in_origin(L_*temp, '1)</td></tr>
    <tr><td>loan_in_origin(L_*temp, 't0)</td></tr>
    <tr><td>loan_in_origin(L_*temp, 'v)</td></tr>
    </table>> ]
    C -> D

    E [ label = <<table border="0">
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, 'temp)</td></tr>
    <tr><td>subset('0, '1)</td></tr>
    <tr><td>subset('0, 't0)</td></tr>
    <tr><td>subset('0, 'v)</td></tr>
    <tr><td>subset('temp, '1)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('1, 't0)</td></tr>
    <tr><td>subset('1, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'temp)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '1)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 't0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'v)</td></tr>
    <tr><td>loan_in_origin(L_*temp, '1)</td></tr>
    <tr><td>loan_in_origin(L_*temp, 't0)</td></tr>
    <tr><td>loan_in_origin(L_*temp, 'v)</td></tr>
    </table>> ]
    C -> E

    F [ label = <<table border="0">
    <tr><td>-------------------</td></tr>
    <tr><td>subset('0, '1)</td></tr>
    <tr><td>subset('0, 't0)</td></tr>
    <tr><td>subset('0, 'v)</td></tr>
    <tr><td>subset('0, 'temp)</td></tr>
    <tr><td>subset('1, 't0)</td></tr>
    <tr><td>subset('1, 'v)</td></tr>
    <tr><td>subset('1, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, '1)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 't0)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'v)</td></tr>
    <tr><td>loan_in_origin(L_Thing, 'temp)</td></tr>
    </table>> ]
    E -> F
    D -> F
    F -> C

}
```

### Example vec-temp

This illustrates why we propagate subtype relations.

```rust
let mut x = 22;
let mut v = vec![];
let p = &x;
let mut tmp = &mut v;
Vec::push(tmp, p);
x = 23;
Vec::len(v); // ERROR
```

```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 

    Decls [ label = <<table border="0">
    <tr><td align="left">let x:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let v:</td>
        <td align="left">Vec&lt;&amp;'v mut u32&gt;</td></tr>
    <tr><td align="left">let p:</td>
        <td align="left">&amp;'p u32</td></tr>
    <tr><td align="left">let tmp:</td>
        <td align="left">&amp;'tmp0 mut Vec&lt;&amp;'tmp1 mut u32&gt;</td></tr>
    <tr><td align="left">L_x:</td>
        <td align="left">shared(x)</td></tr>
    <tr><td align="left">L_v:</td>
        <td align="left">mutable(v)</td></tr>
    </table>> ]

    A [ label = <<table border="0">
    <tr><td>x = 22</td></tr>
    <tr><td>invalidate_loan(L_x)</td></tr>
    </table>> ]

    B [ label = <<table border="0">
    <tr><td>v = vec![]</td></tr>
    <tr><td>invalidate_loan(L_v)</td></tr>
    </table>> ]
    A -> B

    C [ label = <<table border="0">
    <tr><td>p = &amp;x</td></tr>
    <tr><td>introduce_loan(L_x, 'p)</td></tr>
    </table>> ]
    B -> C

    D [ label = <<table border="0">
    <tr><td>tmp = &amp;mut v</td></tr>
    <tr><td>introduce_loan('tmp0, L_v)</td></tr>
    <tr><td>introduce_subset('tmp1, 'v)</td></tr>
    <tr><td>introduce_subset('v, 'tmp1)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>loan_in_origin(L_x, 'p)</td></tr>
    </table>> ]
    C -> D

    E [ label = <<table border="0">
    <tr><td>Vec::push(tmp, p)</td></tr>
    <tr><td>access_origin('tmp0)</td></tr>
    <tr><td>access_origin('tmp1)</td></tr>
    <tr><td>access_origin('p)</td></tr>
    <tr><td>introduce_subset('p, 'tmp1)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('tmp1, 'v)</td></tr>
    <tr><td>subset('v, 'tmp1)</td></tr>
    <tr><td>loan_in_origin(L_v, 'tmp0)</td></tr>
    <tr><td>loan_in_origin(L_x, 'p)</td></tr>
    </table>> ]
    D -> E

    F [ label = <<table border="0">
    <tr><td>x = 23</td></tr>
    <tr><td>invalidate_loan(L_x)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('tmp1, 'v)</td></tr>
    <tr><td>subset('v, 'tmp1)</td></tr>
    <tr><td>subset('p, 'tmp1)</td></tr>
    <tr><td>loan_in_origin(L_v, 'tmp0)</td></tr>
    <tr><td>loan_in_origin(L_x, 'p)</td></tr>
    <tr><td>loan_in_origin(L_x, 'tmp1)</td></tr>
    <tr><td>loan_in_origin(L_x, 'v)</td></tr>
    </table>> ]
    E -> F
    
    G [ label = <<table border="0">
    <tr><td>Vec::len(v)</td></tr>
    <tr><td>access_origin('v)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('tmp1, 'v)</td></tr>
    <tr><td>subset('v, 'tmp1)</td></tr>
    <tr><td>subset('p, 'tmp1)</td></tr>
    <tr><td>origin_invalidated('tmp1)</td></tr>
    <tr><td>origin_invalidated('v)</td></tr>
    <tr><td>invalidated_origin_accessed('v)</td></tr>
    </table>> ]
    F -> G
}
```

### Example killing-and-murder

```rust
let p = 22;
let q = 44;
let x: &mut i32 = &mut p; // `x` points at `p`
let y = &mut *x; // Loan L0, `y` points at `p` too
// ...
x = &mut q; // `x` points at `q`; clears L0
```


```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 

    Decls [ label = <<table border="0">
    <tr><td align="left">let p:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let q:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let x:</td>
        <td align="left">&amp;'x mut i32</td></tr>
    <tr><td align="left">let y:</td>
        <td align="left">&amp;'y mut i32</td></tr>
    <tr><td align="left">L_p:</td>
        <td align="left">mut(p)</td></tr>
    <tr><td align="left">L_q:</td>
        <td align="left">mut(q)</td></tr>
    <tr><td align="left">L_*x:</td>
        <td align="left">mut(*x)</td></tr>
    </table>> ]

    A [ label = <<table border="0">
    <tr><td>p = 22</td></tr>
    <tr><td>invalidate_loan(L_p)</td></tr>
    </table>> ]

    B [ label = <<table border="0">
    <tr><td>q = 22</td></tr>
    <tr><td>invalidate_loan(L_q)</td></tr>
    </table>> ]
    A -> B

    C [ label = <<table border="0">
    <tr><td>x = &amp;'0 mut p</td></tr>
    <tr><td>invalidate_loan(L_q)</td></tr>
    </table>> ]
    B -> C

}
```

### Example Dylan's Canonical Liveness

```rust
let x = 22;
let y = 44;
let mut p: &'0 i32 = &'1 x; // Loan L0
p = &'3 y; // Loan L1
x += 1;   // invalidates(L0)
print(*p);
```


```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 

    Decls [ label = <<table border="0">
    <tr><td align="left">let p:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let q:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let x:</td>
        <td align="left">&amp;'x mut i32</td></tr>
    <tr><td align="left">let y:</td>
        <td align="left">&amp;'y mut i32</td></tr>
    <tr><td align="left">L_p:</td>
        <td align="left">mut(p)</td></tr>
    <tr><td align="left">L_q:</td>
        <td align="left">mut(q)</td></tr>
    <tr><td align="left">L_*x:</td>
        <td align="left">mut(*x)</td></tr>
    </table>> ]

    A [ label = <<table border="0">
    <tr><td>p = 22</td></tr>
    <tr><td>invalidate_loan(L_p)</td></tr>
    </table>> ]

    B [ label = <<table border="0">
    <tr><td>q = 22</td></tr>
    <tr><td>invalidate_loan(L_q)</td></tr>
    </table>> ]
    A -> B

}
```

---

### Example vec-push-ref

```rust
let mut x = 22;
let mut v = vec![];
let p = &x;

if something() {
    v.push(p);
    x += 1;
    v.len(); // ERROR
} else {
    x += 1;
    v.len(); // OK
}

v.len(); // ERROR
```

```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ] 

    Decls [ label = <<table border="0">
    <tr><td align="left">let x:</td>
        <td align="left">u32</td></tr>
    <tr><td align="left">let v:</td>
        <td align="left">Vec&lt;&amp;'v mut u32&gt;</td></tr>
    <tr><td align="left">let p:</td>
        <td align="left">&amp;'p u32</td></tr>
    <tr><td align="left">L_x:</td>
        <td align="left">shared(x)</td></tr>
    <tr><td align="left">L_v:</td>
        <td align="left">mutable(*v)</td></tr>
    </table>> ]

}
```


### Example eq-ftw

```rust
#![feature(nll)]
#![allow(unused_variables, unused_assignments)]

fn random_bool() -> bool {
    unimplemented!()
}

fn main() {
    let mut x: (&u32,) = (&0,);
    let mut y: (&u32,) = (&1,);
    let mut z = 2;

    if random_bool() {
        y.0 = x.0; // creates `'x: 'y` subset relation
    }

    if random_bool() {
        x.0 = &z; // creates {L0} in 'x constraint
        // this point, we have `'x: 'y` and `{L0} in `'x`, so we also have `{L0} in 'y`
        drop(x.0);
    }

    z += 1; // polonius flags an (unnecessary) error

    drop(y.0);
}
```

### Example propagation required

```rust
fn cfg_propagation_required(x: &mut &i32) {
    let y = x;
    *y = &g();
}
```

## 47680 unrolled

```graphviz
digraph G {
    rankdir = "TD"
    node [ shape = "rectangle" ]
        a [ label = <<table border="0">
    <tr><td>a: temp = &amp;'L_Thing mut Thing</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>introduce_subset('L_Thing, 'temp)</td></tr>
    </table>> ]    b [ label = <<table border="0">
    <tr><td>b: t0 = &amp;'L_*temp mut *temp</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('temp)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('t0)</td></tr>
    <tr><td>introduce_subset('L_*temp, 't0)</td></tr>
    <tr><td>introduce_subset('temp, 'L_*temp)</td></tr>
    <tr><td>invalidate_origin('L_*temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    </table>> ]    a -> b
    b1 [ label = <<table border="0">
    <tr><td>b1: t0 = &amp;'L_*temp mut *temp</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('temp)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('t0)</td></tr>
    <tr><td>introduce_subset('L_*temp, 't0)</td></tr>
    <tr><td>introduce_subset('temp, 'L_*temp)</td></tr>
    <tr><td>invalidate_origin('L_*temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    f -> b1
    b2 [ label = <<table border="0">
    <tr><td>b2: t0 = &amp;'L_*temp mut *temp</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('temp)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('t0)</td></tr>
    <tr><td>introduce_subset('L_*temp, 't0)</td></tr>
    <tr><td>introduce_subset('temp, 'L_*temp)</td></tr>
    <tr><td>invalidate_origin('L_*temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td bgcolor= "yellow">invalidated_origin_accessed('temp)</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    f1 -> b2
    b3 [ label = <<table border="0">
    <tr><td>b3: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    f2 -> b3
    c [ label = <<table border="0">
    <tr><td>c: v = MaybeNext(t0)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('t0)</td></tr>
    <tr><td>clear_origin('v)</td></tr>
    <tr><td>introduce_subset('t0, 'v)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    </table>> ]    b -> c
    c1 [ label = <<table border="0">
    <tr><td>c1: v = MaybeNext(t0)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('t0)</td></tr>
    <tr><td>clear_origin('v)</td></tr>
    <tr><td>introduce_subset('t0, 'v)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>origin_invalidated('v)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    b1 -> c1
    c2 [ label = <<table border="0">
    <tr><td>c2: v = MaybeNext(t0)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('t0)</td></tr>
    <tr><td>clear_origin('v)</td></tr>
    <tr><td>introduce_subset('t0, 'v)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>origin_invalidated('v)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    b2 -> c2
    d [ label = <<table border="0">
    <tr><td>d: temp = v</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('v)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('temp)</td></tr>
    <tr><td>introduce_subset('v, 'temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c -> d
    d1 [ label = <<table border="0">
    <tr><td>d1: temp = v</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('v)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('temp)</td></tr>
    <tr><td>introduce_subset('v, 'temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c1 -> d1
    d2 [ label = <<table border="0">
    <tr><td>d2: temp = v</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>access_origin('v)</td></tr>
    <tr><td>clear_origin('L_*temp)</td></tr>
    <tr><td>clear_origin('temp)</td></tr>
    <tr><td>introduce_subset('v, 'temp)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c2 -> d2
    e [ label = <<table border="0">
    <tr><td>e: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c -> e
    e1 [ label = <<table border="0">
    <tr><td>e1: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c1 -> e1
    e2 [ label = <<table border="0">
    <tr><td>e2: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    c2 -> e2
    f [ label = <<table border="0">
    <tr><td>f: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    g -> f    h -> f
    f1 [ label = <<table border="0">
    <tr><td>f1: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    g1 -> f1    h1 -> f1
    f2 [ label = <<table border="0">
    <tr><td>f2: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 'L_*temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'temp)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'L_*temp)</td></tr>
    <tr><td>subset('t0, 't0)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    <tr><td>subset('v, 'L_*temp)</td></tr>
    <tr><td>subset('v, 't0)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    <tr><td>subset('v, 'v)</td></tr>
    </table>> ]    g2 -> f2    h2 -> f2
    g [ label = <<table border="0">
    <tr><td>g: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    </table>> ]    d -> g
    g1 [ label = <<table border="0">
    <tr><td>g1: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    </table>> ]    d1 -> g1
    g2 [ label = <<table border="0">
    <tr><td>g2: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'temp)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('v, 'temp)</td></tr>
    </table>> ]    d2 -> g2
    h [ label = <<table border="0">
    <tr><td>h: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    e -> h
    h1 [ label = <<table border="0">
    <tr><td>h1: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    e1 -> h1
    h2 [ label = <<table border="0">
    <tr><td>h2: (pass)</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>-------------------</td></tr>
    <tr><td>origin_invalidated('temp)</td></tr>
    <tr><td>subset('L_*temp, 't0)</td></tr>
    <tr><td>subset('L_*temp, 'v)</td></tr>
    <tr><td>subset('L_Thing, 'L_*temp)</td></tr>
    <tr><td>subset('L_Thing, 't0)</td></tr>
    <tr><td>subset('L_Thing, 'temp)</td></tr>
    <tr><td>subset('L_Thing, 'v)</td></tr>
    <tr><td>subset('t0, 'v)</td></tr>
    <tr><td>subset('temp, 'L_*temp)</td></tr>
    <tr><td>subset('temp, 't0)</td></tr>
    <tr><td>subset('temp, 'temp)</td></tr>
    <tr><td>subset('temp, 'v)</td></tr>
    </table>> ]    e2 -> h2
}
```

## Niko's concern

```
A -> B
A -> C

where

A has subsets:
    o0 <= o1
    o2 <= o3

A introduces o1 <= o2

o1, o2 are live in B
o1, o2 are dead in C
```

Shouldn't we have `o0 <= o3` in C? I don't think we will.

Is another way to phrase this `subset_on_entry` vs `subset_on_exit`? I think so. In that case, it makes sense that we:

* Apply kills/liveness when transitioning from entry => exit
* Apply liveness when we transition exit => entry (along cfg edges)
* But never apply both

Or rather

```
exit = entry - cleared + introduced live
```

but we could also reduce this to *just* compute subset on entry, couldn't we?

```
subset_on_exit(O1, O2, Node) =
    subset_on_entry(O1, O2, Node),
    !clear_origin(O1, Node),
    !clear_origin(O2, Node).

subset_on_exit(O1, O2, Node) =
    introduce_subset(O1, O2, Node).

subset_on_exit(O1, O3, Node) =
    subset_on_exit(O1, O2, Node).
    subset_on_exit(O2, O3, Node).

subset_on_entry(O1, O2, Node) =
    cfg_edge(Node_pred, Node),
    subset_on_exit(O1, O2, Node_pred),
    (
        is_loan_origin(O1); 
        origin_live_on_entry(O1, Node),
        origin_live_on_entry(O2, Node)
    ).


origin_live_on_entry(O, Node) :-
    access_origin(O, Node).
    
origin_live_on_entry(O, Node) :-
    cfg_edge(Node, Node_succ),
    origin_live_on_entry(O, Node_succ),
    !clear_origin(O, Node).
```




---

// * First we perform any accesses `access_origin(O, N)`
// * Then we invalidate any origins `invalidate_origin(L, N)`
// * Then we clear any origins `clear_origin`
// * Then we introduce any subsets `introduce_subset`

---

Why this matters

* On entry:
    * O1 <= O2
    * O2 <= O3
* Clear origins:
    * O3
* Introduced:
    * O3 <= O4
* Result:
    * O1 <= O2
    * O3 <= O4

```
// vec-temp
// let mut x = 22;
// let mut v = vec![];
// let p = &x;
// let mut tmp = &mut v;
// Vec::push(tmp, p);
// x = 23;
// Vec::len(v); // ERROR
```