# Polonius 2022-11-02 Hackathon Master Document
## Agenda
* Introductions
* Review and discuss goals
* including those that are publishable work for Amanda
* Review the polonius.next rules
* compare with the original rules
* (also: the claim that they are not equivalent and polonius.next's `clear_origin` would allow patterns that regular polonius wouldn't)
* Possible reports:
* Experience and insights from integration with a-mir-formality (nikomatsakis)
## Links
* https://github.com/nikomatsakis/polonius.next/
* borrowck in a-mir-formality
* https://github.com/nikomatsakis/a-mir-formality/pull/110 and https://github.com/nikomatsakis/a-mir-formality/pull/111
* more polonius-like https://github.com/nikomatsakis/a-mir-formality/pull/113
## Goals for the day
* Breakdown of tasks, clarity around who would do what
* Plans for next hackathon
## architectural design
```mermaid
flowchart TD
MirConstruction --produces --> DefaultMir
DefaultMir -- read by --> InitializationAnalysis
DefaultMir[(Default MIR)]
InitializationAnalysis -- produces --> DropElaboratedMir
DropElaboratedMir[(Drop-elaborated MIR)]
DropElaboratedMir -- read by --> MirTypeChecker
MirTypeChecker -- produces --> TypeCheckConstraints
TypeCheckConstraints[(Type-check constraints)]
TypeCheckConstraints -- read by --> LoanAnalysis
DropElaboratedMir -- read by --> LoanAnalysis
TypeCheckConstraints -- read by --> SubsetAnalysis
DropElaboratedMir -- read by --> SubsetAnalysis
subgraph Polonius
LoanAnalysis
SubsetAnalysis
end
```
## task listing
```mermaid
flowchart TD
drop_if_refactoring["
drop-if-refactoring: use `DROP_IF` in
representation of Drop-Elaborated MIR
"]
class drop_if_refactoring nice_to_have;
shallow_subtyping["
shallow-subtyping: resolve higher-ranked
outlives constraints in trait solver
"]
class shallow_subtyping active_development;
extract_mir_to_library["
extract-mir-to-library: represent MIR
as a separate library
"]
class extract_mir_to_library nice_to_have;
loan_analysis_rules["
loan-analysis-rules: draft polonius.next and polonius
into rules for loan-analysis, specify fact generation
"]
class loan_analysis_rules active_development;
loan_analysis_code_complete["
loan-analysis-code-complete: implement
loan analysis in rustc
"]
class loan_analysis_code_complete blocking;
loan_analysis_passing_test_suite["
loan-analysis-passing-test-suite: go through every regression
and fix the problems, address issues found by user testing
"]
class loan_analysis_passing_test_suite blocking;
loan_analysis_in_mir_formality["
loan-analysis-in-mir-formality: model loan-analysis
rules in mir-formality
"]
class loan_analysis_in_mir_formality blocking;
polonius_fuzzer["
polonius-fuzzer: generate programs and check if polonius
diverges from compiler
"]
class polonius_fuzzer nice_to_have;
ship_polonius_crate["
ship-polonius-crate: polonius ships as an independent thing
that can be used outside of rustc, from crates.io
"]
class ship_polonius_crate blocking;
drop_if_refactoring -..-> loan_analysis_code_complete
loan_analysis_rules --> loan_analysis_code_complete
loan_analysis_rules --> loan_analysis_in_mir_formality
loan_analysis_in_mir_formality --> polonius_fuzzer
loan_analysis_code_complete --> loan_analysis_passing_test_suite
shallow_subtyping --> loan_analysis_passing_test_suite
loan_analysis_code_complete --> polonius_fuzzer
polonius_fuzzer -..-> loan_analysis_passing_test_suite
loan_analysis_passing_test_suite --> ship_polonius_crate
extract_mir_to_library --> ship_polonius_crate
classDef nice_to_have fill:#7FDBFF,color:black
classDef blocking fill:#0074D9,color:white
classDef active_development fill:#B10DC9,color:white
```
<span style="background: #7FDBFF; padding: 2px 5px; border-radius: 3px">Cyan things</span> are "nice to have"
<span style="background: #0074D9; color: white; padding: 2px 5px; border-radius: 3px">Blue things</span> are "blocking a stable polonius"
<span style="background: #B10DC9; color: white; padding: 2px 5px; border-radius: 3px">Purple things</span> are "under active development"
### examples
```rust
fn foo<'a>(x: &'a u32)
where
for<'b> 'a: 'b, // effectively the same as `'a: 'static`
{
/* */
}
fn main() {
let mut x = 22;
let p: &i32 = &x;
foo(p);
x += 1; // error
}
```
in the compiler today.
Produce MIR for `main`
```
main() {
let x: i32;
let p: &'0 i32;
BB0 {
p = &'1 x; // &'1 i32 <: &'0 i32 ===> '1: '0
foo(p) returns BB1; // for<'b> '0: 'b ===>
// adds a constraint `for<'b> '0: 'b` to the borrow checker
}
BB1 {
x += 1;
StorageDead(x);
}
}
```
* Today, the output from MIR type checking are constraints like:
* `for<'v...> 'r0: 'r1`
* Borrow check to take those as input and figure out what they mean
* it figures out that this means `'0: 'static`
* `'0` includes all points in the CFG
* `'1` outlives `'0` -- so it too includes all points in the CFG
* reports an error at `x += 1` is inside `'1`
How nikomatsakis expects it to work when we're done:
* MIR type checker (or trait solver) deals with higher-ranked stuff and only emits constraints of the form
* `r0: 'r1`
* So in this example:
* `foo(p)` would yield a constraint like `'0: 'static`
* Polonius would take that as input and, based on it, figure out that `x += 1` is an error
### examples
```rust
fn foo<'a>(x: &'a u32)
where
for<'b> if ('a: 'b) 'a: 'b, // gets derived by
for<'b> fn(&'b &'a u32) : Ord, // proving that `fn` is well-formed here
{
/* */
}
fn main() {
let mut x = 22;
let p: &i32 = &x;
foo(p);
x += 1; // error
}
```
### reviewing the rules
https://github.com/nikomatsakis/polonius.next/blob/main/src/polonius.dl
https://hackmd.io/CGMNjt1hR_qYtsR9hgdGmw
### polonius.next
```rust
let mut x = 1;
let p = &x; // p: &{O0} i32, O0 includes x
x += 1; // invalid = {x}
drop(p); // error: use of reference with invalidated origin (`x`)
```
* compute live variables at each point
* for each origin that appears in their type, call that origin live at that point
* for each `&'0 x` expression in the MIR, create a loan L0
* and require that `'0` includes `{L0}`
* propagate these using dataflow
* gives rise to, each point:
* origin includes some set of loans L...
* set set of origins O... are live
* if a live origin O includes a loan L,
* and the node takes an action that contradicts L,
* then you have an error
* work item:
* merge liveness into polonius.next to produce the preferred rules
* simplify polonius to remove before/after nodes and to remove initialization, liveness computation
```rust
impl LinkedList {
fn get_next(&mut self) -> Option<&mut Self>;
}
fn foo(tmp: &mut LinkedList) {
loop {
match get_next(tmp) {
Some(p) => {
tmp = p;
}
None => { }
}
}
}
```
* compiler can tell us the live origins at each point
* https://github.com/domenicquirl/polonius.next/blob/subset-paths/src/polonius.dl
### location insensitive variant of polonius
* loan active is a dataflow computation:
* loans become active when they are issued (at the `&x` instruction)
* loans are killed when the path that was borrowed is mutated
* propagate till fixed point
```rust
fn main() {
let mut x = 3;
// L0 is not active here
let p = &x; // loan L0
// L0 is active here
drop(p); // p goes dead here
// L0 is still active here
x = 5; // this mutates the path that was borrowed
// loan is inactive
}
```
* every origin maps to a set of loans that you are computing
* MIR type check produces `'a: 'b` constraints
* if some point P has an action that contradicts loan L and L is active at P:
* search each live origin O at P
* report an error if O contains L
```
inputs:
subset(O1, O2).
borrow_loan(O, L).
error(P) :-
contradicts(P, L),
loan_active(L, P),
live_origin(P, O),
contains_loan(O, L).
contains_loan(O, L) :-
contains_loan(O1, L),
subset(O1, O).
contains_loan(O, L) :-
borrow_loan(O, L).
```
https://github.com/rust-lang/polonius/blob/master/polonius-engine/src/output/location_insensitive.rs
purely forward propagation errors and thoughts: https://hackmd.io/KpK0ICQOQLSPxIcNIlhkJQ
## Follow-up items
* figuring out the spec (nikomatsakis driving to some extent :)
* a-mir-formality / coordinate on types team stream?
* implement MIR + MIR type checker (to some extent) on the riir branch of a-mir-formality https://github.com/nikomatsakis/a-mir-formality/tree/riir
* port redex rules for NLL to that
* update on current status of .next rules, and in-progress work
* to compare with regular rules
* check the claim that they maybe are not equivalent in expressive power
* domenicquirl to look at that first
* simplify existing polonius rules to remove CFG points / strip down to the loan check
* lqd to pick that up next
* prototyping an actual impl (lqd driving)
* factor out the universe logic to simplify higher-ranked constraints
* theo
* prototype "polonius-style" checker in rustc
* lqd could follow-up / move forward
* assess current status of test suite
* theo to pursue (and will look at that first)
* what is working? what fails and why?