Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions tools/hermes/src/aeneas.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::process::Command;

use anyhow::{bail, Context, Result};

use crate::{resolve::Roots, scanner::HermesArtifact};

pub fn run_aeneas(roots: &Roots, artifacts: &[HermesArtifact]) -> Result<()> {
let llbc_root = roots.llbc_root();
let lean_generated_root = roots.lean_generated_root();

for artifact in artifacts {
if artifact.start_from.is_empty() {
log::debug!(
"Skipping artifact '{}' because it has no entry points",
artifact.name.target_name
);
continue;
}

log::debug!("Invoking Aeneas on artifact '{}'...", artifact.name.target_name);

let llbc_path = llbc_root.join(artifact.llbc_file_name());
let output_dir = lean_generated_root.join(artifact.artifact_slug());

std::fs::create_dir_all(&output_dir).context("Failed to create Aeneas output directory")?;

let mut cmd = Command::new("aeneas");

cmd.arg("-backend").arg("lean");
cmd.arg("-dest").arg(&output_dir);
cmd.arg("-split-files");
cmd.arg("-no-lean-default-lakefile");
cmd.arg("-decreases-clauses");
cmd.arg("-abort-on-error");

// TODO: Handle opaque functions (`unsafe(axiom)`).
// We need to parse these from the AST and pass them as `-opaque module::params::...`
cmd.arg(&llbc_path);

log::debug!("Command: {:?}", cmd);

let output = cmd.output().context("Failed to spawn aeneas")?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
bail!(
"Aeneas failed for package '{}' with status: {}\nstderr:\n{}",
artifact.name.package_name,
output.status,
stderr
);
}
}

Ok(())
}
8 changes: 4 additions & 4 deletions tools/hermes/src/charon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use crate::{
};

pub fn run_charon(args: &Args, roots: &Roots, packages: &[HermesArtifact]) -> Result<()> {
let charon_root = roots.charon_root();
let llbc_root = roots.llbc_root();

std::fs::create_dir_all(&charon_root).context("Failed to create charon output directory")?;
std::fs::create_dir_all(&llbc_root).context("Failed to create LLBC output directory")?;

for artifact in packages {
if artifact.start_from.is_empty() {
Expand All @@ -26,8 +26,8 @@ pub fn run_charon(args: &Args, roots: &Roots, packages: &[HermesArtifact]) -> Re
let mut cmd = Command::new("charon");
cmd.arg("cargo");

// Output artifacts to target/hermes/<hash>/charon
let llbc_path = charon_root.join(artifact.llbc_file_name());
// Output artifacts to target/hermes/<hash>/llbc
let llbc_path = llbc_root.join(artifact.llbc_file_name());
log::debug!("Writing .llbc file to {}", llbc_path.display());
cmd.arg("--dest-file").arg(llbc_path);

Expand Down
7 changes: 5 additions & 2 deletions tools/hermes/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod aeneas;
mod charon;
mod diagnostics;
mod errors;
Expand Down Expand Up @@ -37,9 +38,11 @@ fn main() -> anyhow::Result<()> {
let roots = resolve::resolve_roots(&resolve_args)?;
let packages = scanner::scan_workspace(&roots)?;
if packages.is_empty() {
anyhow::bail!("No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.");
log::warn!("No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.");
return Ok(());
}
charon::run_charon(&resolve_args, &roots, &packages)
charon::run_charon(&resolve_args, &roots, &packages)?;
aeneas::run_aeneas(&roots, &packages)
}
}
}
Expand Down
8 changes: 6 additions & 2 deletions tools/hermes/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,12 @@ pub struct Roots {
}

impl Roots {
pub fn charon_root(&self) -> PathBuf {
self.hermes_run_root.join("charon")
pub fn llbc_root(&self) -> PathBuf {
self.hermes_run_root.join("llbc")
}

pub fn lean_generated_root(&self) -> PathBuf {
self.hermes_run_root.join("lean").join("generated")
}
}

Expand Down
14 changes: 11 additions & 3 deletions tools/hermes/src/scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ pub struct HermesArtifact {
}

impl HermesArtifact {
/// Returns the name of the `.llbc` file to use for this artifact.
/// Returns a unique "slug" for this artifact, used for file naming.
///
/// Guarantees uniqueness based on manifest path even if multiple packages
/// have the same name.
pub fn llbc_file_name(&self) -> String {
///
/// Format: `{package_name}-{target_name}-{hash:08x}`
pub fn artifact_slug(&self) -> String {
fn hash<T: Hash>(t: &T) -> u64 {
let mut s = std::collections::hash_map::DefaultHasher::new();
t.hash(&mut s);
Expand All @@ -40,7 +42,13 @@ impl HermesArtifact {
let h1 = hash(&self.name.target_name);
let h2 = hash(&self.target_kind);
let h = hash(&[h0, h1, h2]);
format!("{}-{}-{:08x}.llbc", self.name.package_name, self.name.target_name, h)

format!("{}-{}-{:08x}", self.name.package_name, self.name.target_name, h)
}

/// Returns the name of the `.llbc` file to use for this artifact.
pub fn llbc_file_name(&self) -> String {
format!("{}.llbc", self.artifact_slug())
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
failure
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Charon failed with status
Empty file.
7 changes: 7 additions & 0 deletions tools/hermes/tests/fixtures/cfg_blind_spot/source/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "cfg_blind_spot"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
6 changes: 6 additions & 0 deletions tools/hermes/tests/fixtures/cfg_blind_spot/source/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[cfg(target_os = "haiku")]
mod ghost {
/// ```lean
/// ```
pub fn hidden() {}
}
3 changes: 3 additions & 0 deletions tools/hermes/tests/fixtures/external_path_dep/extra.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// ```lean
/// ```
pub fn foo() {}
5 changes: 5 additions & 0 deletions tools/hermes/tests/fixtures/external_path_dep/hermes.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[[artifact]]
package = "external_path_dep"
target = "external_path_dep"
should_exist = true
kind = "llbc"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "external_path_dep"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[path = "../../../extra.rs"]
mod extra;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
failure
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
error
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "hidden_syntax_error"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[cfg(all())]
mod broken {
fn syntax_error( { // Missing closing parenthesis
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
name = "macro_blind_spot"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// ```lean
/// ```
pub fn foo() {}
11 changes: 2 additions & 9 deletions tools/hermes/tests/fixtures/macro_blind_spot/source/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
macro_rules! make_proof {
() => {
/// ```lean
/// theorem hidden_proof : True := trivial
/// ```
pub fn hidden_proof() {}
}
}
make_proof!();
macro_rules! gen_mod { ($n:ident) => { mod $n; } }
gen_mod!(hidden);
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[External Error] external error
Diagnostic error in charon
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[External Error] std error
Diagnostic error in charon
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
× something bad
╭─[[PROJECT_ROOT]/src/untransformed.rs:1:1]
1 │ pub fn untouched() {}
· ─────┬────
· ╰── oops
╰────
Diagnostic error in charon
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
2 changes: 1 addition & 1 deletion tools/hermes/tests/fixtures/no_specs/expected_status.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
5 changes: 5 additions & 0 deletions tools/hermes/tests/fixtures/orphaned_entry/hermes.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[[artifact]]
package = "orphaned_entry"
target = "orphaned_entry"
should_exist = true
kind = "llbc"
7 changes: 7 additions & 0 deletions tools/hermes/tests/fixtures/orphaned_entry/source/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "orphaned_entry"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
3 changes: 3 additions & 0 deletions tools/hermes/tests/fixtures/orphaned_entry/source/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// ```lean
/// ```
fn private_helper() {}
11 changes: 11 additions & 0 deletions tools/hermes/tests/fixtures/split_personality_mod/hermes.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[artifact]]
package = "split_personality_mod"
target = "split_personality_mod" # The lib target name
should_exist = true
kind = "llbc"

[[artifact]]
package = "split_personality_mod"
target = "split_personality_mod"
should_exist = true
kind = "lean"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "split_personality_mod"
version = "0.1.0"
edition = "2021"

[lib]
path = "src/lib.rs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// ```lean
/// ```
pub fn foo() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod a;
#[path = "a.rs"]
mod b;
Original file line number Diff line number Diff line change
@@ -1 +1 @@
failure
success
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Error: No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
No Hermes annotations (/// ```lean ...) found in the selected targets. Nothing to verify.
Loading
Loading