---
tags: notes
---
# 2022-06-16: Polonius notes
## Biggest picture
```mermaid
flowchart LR
MirTypeChecker
TraitSolver
Polonius
MirTypeChecker -- invokes --> TraitSolver
TraitSolver -- schemes --> MirTypeChecker
MirTypeChecker -- first-order outlives constraints --> Polonius
```
Invokes:
* `Vec<?T>: Foo<?U>`
Scheme `(Scheme ::= (∃ KindedVarIds (implies Goals Term)))`
* `?T = ?U`
* include other inference variables and constraints
https://github.com/nikomatsakis/a-mir-formality/blob/fb940679b0b0c7e8497ed5b3d2ba78a5617634fc/src/ty/grammar.rkt#L18-L19
```rust
trait Foo<X> { }
impl<A> Foo<A> for Vec<A> { }
```
given this
```rust
trait Foo<X> { }
impl<A> Foo<A> for Vec<Box<A>> { }
```
and a goal `Vec<?T>: Foo<?U>`
the answer might be
* `∃A. ?T = Box<A> and ?U = A`
## Polonius inputs
* First-order outlives constraints like `'a: 'b`
* located at a point in the CFG
* `'a: 'b @ P`
* Maybe some `'a: 'b` that have to hold always
* maybe we can eliminate these, but maybe not
* Control-flow graph itself
* some nodes P, Q, ... and some edges P -> Q
```
C := (A : B)
| (C && C)
```
we might also want `C || C`
## Other things the borrow checker does
* checking initialization
"variables never initialized at all"
```rust
let a;
println!("{}", a); // error
```
"variables that are initialized later"
```rust
let a;
if something { a = 10; } else { a = 22; }
println!("{}", a); // OK!
```
"variables that were initialized but have been moved"
```rust
let a = vec![];
std::mem::drop(a);
a = 10; // error
```
"variables that were initialized but may be moved"
```rust
let a = vec![];
if something { std::mem::drop(a); }
a = 10; // error
```
not only variables, also fields "in some cases"
```rust
let mut tuple = (vec![], vec![]);
std::mem::drop(tuple.0);
println!("{:?}", tuple.1);
```
## Polonius inputs
* First-order outlives constraints like `'a: 'b`
* located at a point in the CFG
* `'a: 'b @ P`
* Maybe some `'a: 'b` that have to hold always
* maybe we can eliminate these, but maybe not
* Control-flow graph itself
* some nodes P, Q, ... and some edges P -> Q
* Moves that occur and what is moved
## Phasing
* initialization analysis
* checks that all data is initialized
* liveness
## Optimization potential
* flow-insensitive
* if no back-edges, don't need liveness, etc
## drop elaboration?
```rust
{
let x = Box::new(22);
...
// DROP(x);
}
```
```rust
{
let x = Box::new(22);
std::mem::drop(x);
// DROP(x); -- noop
}
```
```rust
{
let x = Box::new(22);
if something {
std::mem::drop(x);
}
// DROP(x); -- noop?
}
```
```rust
{
let x = Box::new(22);
let x_init = true;
if something {
x_init = false;
std::mem::drop(x);
}
// if x_init { DROP(x); } -- noop?
}
```
## drop-if alternative
instead of `DROP(x)` meaning
"drop x if x is initialized"
we could have `DROP_IF(condition, x)`
"if condition is true, drop x"
and a "extra" guarantee that at the time of MIR borrow check, condition is true iff x is initialized
```rust
{
let x = Box::new(22);
if something {
std::mem::drop(x);
}
// DROP_IF(true, x)
}
```
```rust
{
let x = Box::new(22);
let x_init = true;
if something {
x_init = false;
std::mem::drop(x);
}
// DROP_IF(x_init, x)
}
```
```rust
{
let tuple = (Box::new(22), Box::new(44));
if something {
std::mem::drop(tuple);
}
// DROP(tuple) -- at time of MIR build
// DROP(tuple.1) -- after elaboration
}
```
```rust
{
let tuple = (Box::new(22), Box::new(44));
if something {
std::mem::drop(tuple);
}
// DROP_IF(tuple) -- at time of MIR build
// DROP_IF(tuple.1) -- after elaboration
}
```
the upshot is:
* we can have a version of drop elaboration that produces a `DROP_IF` which the borrow checker can just treat as "always a use"
* which would be nice :)
## What exactly region analysis
```rust
{
let (x, y) = (Box::new(), Box::new());
}
```
```rust
let x = Box::new(22);
let y = &L0 x;
// y is live here
//
// therefore, loan L0 is live
//
// therefore x cannot be dropped, mutated etc
std::mem::drop(y);
```
## Pieces of work that are needed
```mermaid
flowchart LR
drop_if
move_init_formality
loan_formality
drop_if --> move_init_formality
```
* drop-if refactoring :)
* move-init / formality
* formality of the "loan" analysis
* an efficient impl of the "loan" analysis
* depends on "shallow subtyping" work that is going on
* Settle the mir-formality "fully correct" rules
* Create an efficient implementation
## overall dataflow (goal)
```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"
## Detailed look at various items
### DropIfRefactoring
[discussion here](https://rust-lang.zulipchat.com/#narrow/stream/186049-t-compiler.2Fwg-polonius/topic/2022-08/near/295224824)
###