https://github.com/coord-e/thrust
Refinement type checking and inference tool for Rust
https://github.com/coord-e/thrust
Last synced: 3 months ago
JSON representation
Refinement type checking and inference tool for Rust
- Host: GitHub
- URL: https://github.com/coord-e/thrust
- Owner: coord-e
- Created: 2024-05-13T11:07:18.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-30T15:34:47.000Z (3 months ago)
- Last Synced: 2026-03-30T16:37:20.398Z (3 months ago)
- Language: Rust
- Homepage:
- Size: 599 KB
- Stars: 20
- Watchers: 2
- Forks: 1
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Thrust
Thrust is a refinement type checking and inference tool for Rust.
## Getting Started
- Make sure [Z3](https://github.com/Z3Prover/z3) is installed.
- The main binary, `thrust-rustc`, behaves like `rustc` but includes Thrust's verification.
- In the following instructions, we assume the Thrust source code is cloned locally and commands are executed within it.
Take the following Rust code (`gcd.rs`):
```rust
fn gcd(mut a: i32, mut b: i32) -> i32 {
while a != b {
let (l, r) = if a < b {
(&mut a, &b)
} else {
(&mut b, &a)
};
*l -= *r;
}
a
}
#[thrust::callable]
fn check_gcd(a: i32, b: i32) {
assert!(gcd(a, b) <= a);
}
fn main() {}
```
Let Thrust verify that the program is correct. Here, we use `cargo run` in the Thrust source tree to build and run `thrust-rustc`. Note that you need to disable the debug overflow assertions in rustc, as they are currently not supported in Thrust.
```console
$ cargo run -- -Adead_code -C debug-assertions=false gcd.rs && echo 'safe'
Compiling thrust v0.1.0 (/home/coord_e/rust-refinement/thrust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/thrust-rustc -Adead_code -C debug-assertions=false gcd.rs`
error: verification error: Unsat
error: aborting due to 1 previous error
```
Thrust says the program is not safe (possible to panic). In fact, we have a bug in our `gcd` function:
```diff
fn gcd(mut a: i32, mut b: i32) -> i32 {
while a != b {
- let (l, r) = if a < b {
+ let (l, r) = if a > b {
(&mut a, &b)
} else {
(&mut b, &a)
```
Now Thrust verifies the program is actually safe.
```console
$ cargo run -- -Adead_code -C debug-assertions=false gcd_fixed.rs && echo 'safe'
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/thrust-rustc -Adead_code -C debug-assertions=false gcd.rs`
safe
```
Integration test examples are located under `tests/ui/` and can be executed using `cargo test`. You can review these examples to understand what the current Thrust implementation can handle.
## Annotation
Thrust can verify a wide range of programs without explicit annotations, but you can use `#[thrust::requires(expr)]` and `#[thrust::ensures(expr)]` to annotate the precondition and postcondition of a function, aiding in verification or specifying the specification. Here, `expr` is a logical expression that supports basic integer, boolean, and reference operations.
```rust
#[thrust::requires(n >= 0)]
#[thrust::ensures((result * 2) == n * (n + 1))]
fn sum(n: i32) -> i32 {
if n == 0 {
0
} else {
n + sum(n - 1)
}
}
```
You can use the `^` unary operator to denote the value of a mutable reference after the function is called. Note that in the current implementation, you need to specify both `requires` and `ensures` when using either one.
```rust
#[thrust::requires(true)]
#[thrust::ensures(^ma == *ma + a)]
fn add(ma: &mut i32, a: i32) {
*ma += a;
}
```
The conditions on `thrust::requires` and `thrust::ensures` are internally encoded as refinement types for the parameter and return types. You can also specify these refinement types directly using `#[thrust::param(param: type)]` and `#[thrust::ret(type)]`.
```rust
#[thrust::param(n: { x: int | x >= 0 })]
#[thrust::ret({ x: int | (x * 2) == n * (n + 1) })]
fn sum(n: i32) -> i32 {
if n == 0 {
0
} else {
n + sum(n - 1)
}
}
```
The bodies of functions marked with `#[thrust::trusted]` are not analyzed by Thrust. Additionally, `#[thrust::callable]` is an alias for `#[thrust::requires(true)]` and `#[thrust::ensures(true)]`.
```rust
#[thrust::trusted]
#[thrust::callable]
fn rand() -> i32 { unimplemented!() }
```
## Configuration
Several environment variables are used by Thrust to configure its behavior:
- `THRUST_SOLVER`: A CHC solver command used to solve CHC constraints generated by Thrust. Default: `z3`
- `THRUST_SOLVER_ARGS`: Whitespace-separated command-line flags passed to the solver. The default is `fp.spacer.global=true fp.validate=true` when the solver is `z3`.
- `THRUST_SOLVER_TIMEOUT_SECS`: Timeout for waiting on results from the solver. Default: `30`
- `THRUST_OUTPUT_DIR`: When configured, Thrust outputs intermediate smtlib2 files into this directory.
- `THRUST_ENUM_EXPANSION_DEPTH_LIMIT`: When Thrust works with enums, it "expands" the structure of the enum value onto its environment. This configuration value sets the limit on the depth of recursion during this expansion to handle enums that are defined recursively. It is our future work to discover a sensible value for this automatically. Default: `2`
## Development
The implementation of the Thrust is largely divided into the following modules.
- `analyze`: MIR analysis. Further divided into the modules corresponding to the program units: `analyze::crate_`, `analyze::local_def`, and `analyze::basic_block`.
- `refine`: Typing environment and related implementations.
- `rty`: Refinement type primitives.
- `chc`: CHC and logic primitives, and it also implements an invocation of the underlying CHC solver.
- `annot`: Refinement type annotation parser.
The implementation generates subtyping constraints in the form of CHCs (`chc::System`). The entry point is `analyze::crate_::Analyzer::run`, followed by `analyze::local_def::Analyzer::run` and `analyze::basic_block::Analyzer::run`, while accumulating the necessary information in `analyze::Analyzer`. Once `chc::System` is collected for the entire input, it invokes an external CHC solver via the `chc::solver` module and subsequently reports the result.
## Publication
Hiromi Ogawa, Taro Sekiyama, and Hiroshi Unno. Thrust: A Prophecy-based Refinement Type System for Rust. PLDI 2025.
## License
Licensed under either of
* Apache License, Version 2.0
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.