Skip to content

Commit 142c395

Browse files
authored
[hermes] Check llms-full.txt in CI (#3194)
Makes progress on #3152 gherrit-pr-id: Gqdqcqcelrxsnq77ga5y3cnwtq46kh7mc
1 parent 66a6d7e commit 142c395

File tree

130 files changed

+840852
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+840852
-57
lines changed

.github/workflows/hermes.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ jobs:
4848
cache-from: type=gha
4949
cache-to: type=gha,mode=max
5050

51+
# Ensure `llms-full.txt` file is up-to-date.
52+
- name: Check doc generation
53+
run: docker run --rm -v $GITHUB_WORKSPACE/hermes:/workspace hermes-ci:local cargo run -p doc_gen -- --check
54+
5155
# Run unit tests separately, as they're much less likely to have bugs
5256
# during local development, and this makes the GitHub Actions output
5357
# easier to skim (in particular, it's clear at a glance whether a failure

hermes/Cargo.lock

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hermes/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[workspace]
2+
members = [".", "tools/doc_gen"]
23

34
[package]
45
name = "cargo-hermes"

hermes/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ COPY build.rs build.rs
3737
COPY src src
3838
# Since Cargo.toml explicitly declares [[test]] "integration", this file must exist for Cargo to parse it.
3939
COPY tests/integration.rs tests/integration.rs
40+
# Copy tools because they are part of the workspace members
41+
COPY tools tools
4042

4143
# Download and verify the required versions of Charon and Aeneas.
4244
RUN cargo run --bin cargo-hermes setup && \

hermes/llms-full.txt

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ Hermes specifications are written directly in your Rust source code using specia
267267

268268
## 1. Annotation Chains
269269

270-
To attach a specification to a function, struct, or trait, write a `///` doc-comment block immediately preceding the definition.
270+
To attach a specification to a function, struct, or trait, write a `///` doc-comment block immediately preceding the definition.
271271

272272
The block must begin with the `hermes` language string.
273273
```rust
@@ -298,15 +298,15 @@ In addition to attaching specs directly to items, you can define a standalone bl
298298

299299
Hermes uses a strict, indentation-sensitive parser (similar to Python or YAML). **Whitespace is semantically significant.**
300300

301-
The rule is simple: **Any line that is indented further than the leading clause belongs to that clause.**
301+
The rule is simple: **Any line that is indented further than the leading clause belongs to that clause.**
302302
If you break an expression across multiple lines, every continuation line *must* be indented deeper than the line that started it.
303303

304304
**Valid:**
305305
```rust
306306
/// ```hermes
307307
/// requires:
308308
/// let x = 5
309-
/// let y =
309+
/// let y =
310310
/// x + 2
311311
/// ```
312312
```
@@ -316,7 +316,7 @@ If you break an expression across multiple lines, every continuation line *must*
316316
/// ```hermes
317317
/// requires:
318318
/// let x = 5
319-
/// let y =
319+
/// let y =
320320
/// x + 2 <-- ERROR: Not indented deeper than `let y =`
321321
/// ```
322322
```
@@ -339,7 +339,7 @@ However, Hermes explicitly disables standard implicits in favor of **Strict Impl
339339

340340
**Why is this required?**
341341
Standard implicits (`{}`) instruct Lean to eagerly guess and synthesize the typeclass immediately when the function is evaluated. For complex spatial traits (like `HasStaticLayout`), this eager synthesis often panics the solver before the proof even begins.
342-
Strict implicits (`{{ }}`) politely instruct Lean to *delay* synthesis until the exact moment the trait is actively applied to a concrete value.
342+
Strict implicits (`{{ }}`) politely instruct Lean to *delay* synthesis until the exact moment the trait is actively applied to a concrete value.
343343

344344
If you are refactoring a Hermes spec, do not replace `{{_sz: Sized Self}}` with `{_sz: Sized Self}`. You will likely break downstream proofs invisibly.
345345

@@ -358,9 +358,9 @@ If you simply write an expression, you are defining an anonymous bound.
358358
/// x > 0
359359
/// ```
360360
```
361-
This requires that `x > 0`. Internally, Hermes names this bound `h_unnamed`.
361+
This requires that `x > 0`. Internally, Hermes names this bound `h_anon`.
362362

363-
**The Singleton Limit:** Because Hermes collapses anonymous bounds into `h_unnamed`, **you may only have one anonymous bound per clause.** If you have multiple requirements, you must name them.
363+
**The Singleton Limit:** Because Hermes collapses anonymous bounds into `h_anon`, **you may only have one anonymous bound per clause.** If you have multiple requirements, you must name them.
364364

365365
### Named Bounds
366366
If multiple `requires` or `ensures` bounds are required, they must be named:
@@ -373,7 +373,7 @@ If multiple `requires` or `ensures` bounds are required, they must be named:
373373
```
374374

375375
Naming your bounds is critical for two reasons:
376-
1. It bypasses the `h_unnamed` singleton limit.
376+
1. It bypasses the `h_anon` singleton limit.
377377
2. It allows you to explicitly reference the proven hypothesis (like `h_x_positive`) in downstream proofs or custom lemmas. Any name you provide here becomes an active variable in the local Lean context during verification.
378378

379379
## 5. Axioms and FFI
@@ -396,7 +396,10 @@ In addition to function-level pre- and post-conditions, Hermes allows you to def
396396

397397
### `isValid`
398398

399-
`isValid` defines a structural invariant for a type.
399+
> [!WARNING]
400+
> `isValid` annotations are currently unsound. To use them, you must provide the `--unsound-allow-is-valid` flag to Hermes.
401+
402+
`isValid` defines a structural invariant for a type.
400403

401404
```rust
402405
/// ```hermes
@@ -421,7 +424,7 @@ Under the hood, this implements the `Hermes.IsValid` typeclass for that struct.
421424
pub unsafe trait Unaligned: Sized {}
422425
```
423426

424-
Implementers of the `unsafe trait` must provide a proof of `isSafe`.
427+
Implementers of the `unsafe trait` must provide a proof of `isSafe`.
425428

426429
**Crucially**, generic functions bounding on the trait (e.g., `fn foo<T: Unaligned>()`) **do not** automatically receive this mathematical assumption in their preconditions, because the trait bound alone does not prove the invariant holds in a generic context. You must explicitly request the `isSafe` property in your `requires` block (see Module 6 for how to consume and apply trait bounds).
427430

@@ -483,7 +486,7 @@ Bounds are namespaced to either pre-conditions or post-conditions. An anonymous
483486

484487
````rust
485488
/// ```hermes
486-
/// isSafe :
489+
/// isSafe :
487490
/// ∀ (self : Self), True
488491
/// ```
489492
````
@@ -510,13 +513,13 @@ pub unsafe fn safe_div(a: u32, b: u32) -> u32 { unsafe { a / b } }
510513

511514
Hermes automatically defines or injects the following structural names.
512515

513-
**`h_unnamed`**: The singleton name assigned to an anonymous `requires` or `ensures` block. These are namespaced to either pre-conditions or post-conditions, so they don't conflict.
516+
**`h_anon`**: The singleton name assigned to an anonymous `requires` or `ensures` block. These are namespaced to either pre-conditions or post-conditions, so they don't conflict.
514517

515518
````rust
516519
/// ```hermes
517-
/// requires: x > 0 -- Named `h_unnamed`
518-
/// ensures: ret = x + 1 -- Named `h_unnamed`
519-
/// proof: -- Proves `h_unnamed`
520+
/// requires: x > 0 -- Named `h_anon`
521+
/// ensures: ret = x + 1 -- Named `h_anon`
522+
/// proof: -- Proves `h_anon`
520523
/// ...
521524
/// ```
522525
````
@@ -558,7 +561,7 @@ fn foo() -> MyType {}
558561
/// proof (h_progress): -- Prove execution doesn't fail (e.g. divide by zero) or loop forever
559562
/// ...
560563
/// ```
561-
fn safe_div(x: u32, y: u32) -> u32 {}
564+
fn safe_div(x: u32, y: u32) -> u32 {}
562565
````
563566

564567
**`h_returns`**: The hypothesis binding the successful evaluation of the function to the implicitly-available values `ret`, `arg'`, etc.
@@ -742,24 +745,24 @@ Writing a Lean proof is not like other forms of software engineering. A Lean pro
742745
The following is a workflow for solving [problem]. It is recursive – you will use this workflow to solve sub-problems as well.
743746

744747
1. Make sure you understand your goal, context, and constraints for [problem] *completely* and *precisely*.
745-
a. Spend as much time as you need *thinking* in order to come to this understanding.
746-
b. If there is any ambiguity whatsoever, ask for clarification.
747-
c. Repeat the process of clarification-asking and thinking until you have a *complete* and *precise* understanding of your goal, context, and constraints.
748-
d. Record this in as much details as you can in comments the file you are editing.
748+
1. Spend as much time as you need *thinking* in order to come to this understanding.
749+
2. If there is any ambiguity whatsoever, ask for clarification.
750+
3. Repeat the process of clarification-asking and thinking until you have a *complete* and *precise* understanding of your goal, context, and constraints.
751+
4. Record this in as much details as you can in comments the file you are editing.
749752
2. Once you understand the goal, context, and constraints for [problem], brainstorm a *complete* solution. Your solution must be *complete*, as the act of thinking through details may make you realize that you need to adjust your high-level plan.
750-
a. Spend as much time as it takes to think through your solution *completely* until you are confident that *every detail* is correct.
751-
b. Record this in as much details as you can in comments the file you are editing.
753+
1. Spend as much time as it takes to think through your solution *completely* until you are confident that *every detail* is correct.
754+
2. Record this in as much details as you can in comments the file you are editing.
752755
3. You are now ready to start writing code.
753-
a. Start with the specification (`requires` and `ensures` clauses).
754-
b. Get these working with the `verify` subcommand and the `--allow-sorry` flag, omitting any proofs.
755-
c. Iterate until everything verifies, implying that your specification is internally consistent. This does not necessarily mean that it's the *right* specification, only that Hermes understands it.
756-
d. Run the `expand` subcommand to see what Lean is generated, and make sure it looks like what you expect. This will help you when you start writing proofs.
756+
1. Start with the specification (`requires` and `ensures` clauses).
757+
2. Get these working with the `verify` subcommand and the `--allow-sorry` flag, omitting any proofs.
758+
3. Iterate until everything verifies, implying that your specification is internally consistent. This does not necessarily mean that it's the *right* specification, only that Hermes understands it.
759+
4. Run the `expand` subcommand to see what Lean is generated, and make sure it looks like what you expect. This will help you when you start writing proofs.
757760
4. Move on to the proof.
758-
a. First, break the proof down into lemmas. Spend as much time as you need thinking through the lemmas and how they fit together to prove the main proof.
759-
b. Write the *definitions* of each lemma, but do *not* prove them – leave their proofs as `sorry` for now.
761+
1. First, break the proof down into lemmas. Spend as much time as you need thinking through the lemmas and how they fit together to prove the main proof.
762+
2. Write the *definitions* of each lemma, but do *not* prove them – leave their proofs as `sorry` for now.
760763
5. Write the top-level proof, using the lemmas you defined in the previous step.
761-
a. Iterate until this proof verifies, using the `--allow-sorry` flag.
762-
b. If you get stuck *at all*, consider whether you need to re-visit a previous step or "pop up" one level of abstraction to reconsider your broader plan.
764+
1. Iterate until this proof verifies, using the `--allow-sorry` flag.
765+
2. If you get stuck *at all*, consider whether you need to re-visit a previous step or "pop up" one level of abstraction to reconsider your broader plan.
763766
6. Once the top-level proof verifies, you can start proving the lemmas one by one. For each lemma, you will use *this entire workflow*, but applied to [sub-problem] instead of the top-level [problem].
764767

765768
Overall, your workflow will look like a recursive application of this entire workflow. Always be prepared to "pop up" one level of abstraction to reconsider your broader plan.

hermes/tools/doc_gen/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "doc_gen"
3+
version = "0.1.0"
4+
edition = "2024"
5+
publish = false
6+
7+
[dependencies]
8+
tree-sitter = "0.25"
9+
tree-sitter-lean4 = "0.2"
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
#!/usr/bin/env -S cargo +nightly -Zscript
2-
---
3-
[dependencies]
4-
tree-sitter = "0.25"
5-
tree-sitter-lean4 = "0.2"
6-
---
7-
81
use std::{env, fs, path::Path, process};
92

103
fn extract_signature(kind: &str, text: &str) -> String {
@@ -122,7 +115,7 @@ fn main() {
122115
let existing = fs::read_to_string(target_file).unwrap_or_default();
123116
if existing != full_txt {
124117
eprintln!(
125-
"Error: {} is out of date. Please run `tools/doc_gen.rs` to update it.",
118+
"Error: {} is out of date. Please run `cargo run -p doc_gen` to update it.",
126119
target_file
127120
);
128121
process::exit(1);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"files":{".cargo_vcs_info.json":"cf43644f4417a371f3b570fae27b3a6949dc254c597474a10b7ee23839965437","AUTHORS":"d5fca2653c88ad02d197faead77e22b80c70636b5bec6e02f2805f389a21b86d","CHANGELOG.md":"33e288ac35f2f0045f692c87624de90f10166e3bd0b3b311eeb7d28560a67aa1","CONTRIBUTING.md":"a7e0f3d282301aa5f4b546ed7fc5376159569987a002f24bf57082d49746fde6","Cargo.lock":"8846412681720cb85ae6a79ac3eae84ca145c7cb4a809e0bd52a3cbaed31ee31","Cargo.toml":"fe2d3062136b9c1bdacc09aaf8ad2766a4182de39732498de8bbb21c62f4384a","Cargo.toml.orig":"fc005fab26a48ff9c66f508c538a84b05cb5b5aea0968acf97daf9092687599a","LICENSE":"3bc70e239e91272782006c638fc0452a714d384224f11f0923036b7be07cf9b5","PERFORMANCE.md":"9de4fa787572943e7e350a2688002d571e986190e4869d08587048974bc2fcc6","README.md":"5321b581e5d6bea76875bc3ef93a482184fea9616b45f73781f5ec16542bdf9c","benches/bench.rs":"ec5005c0ec5b5155ae334f9204dffac98b583c377773dbe81e460ecf7404c1d0","codecov.yml":"d6ebfcadb4d940a0f86ab1a99928b673195c7d84cecee17a5eefeaf396c8477b","examples/toy.rs":"33c5f572f2afa1e0d359845708bd984bc95e272b4dcac0eb3ce55668b2a9d03b","src/analyze.rs":"0ea9e0b9661cef8c804a750459d6caf196b298dae1267d52661f1894f88c47d6","src/compile.rs":"54afdafd8004bc3cd27074e949fb1ccf0c81af0992f9c140141bea8f182ed42c","src/error.rs":"931e720cd907f7f62d41c10b69174f286c2944bb4230df8c3c1428aa75056260","src/expand.rs":"6eff8afef144363d8ebbb90922448783cf2ebfc71ef716948bd9da54793663af","src/lib.rs":"5fceb05786b2e860ec2141c8e6bfbb85014c97b4f48cc634d0842b81b0dd6477","src/parse.rs":"8991c0f8b311f404cd63bc8f2beb898055f14c2fd899ccfb86055b396a596229","src/replacer.rs":"5bf1c99d598c27248fd6591dab000e649eedc8f51179f904e00b94ac27919dc3","src/vm.rs":"8442aec0c60680576130f0ebbd6da494bba14d1141e7035f66c68f3849933731","tests/captures.rs":"0b561bbec208af0cdea12c8b10e3c72eab80ef2dbf1a9c1007fdffc7401b4434","tests/common/mod.rs":"b8ab2a7a3a25adad8317c8eb1f4566df6a81978c3a7ab49847ec2f838d77c888","tests/finding.rs":"76e60d370ae71585a304018fe0398e5206fe431fe21bbde6347cc2572afff0e5","tests/matching.rs":"3f8d1e0f6567375866b14610eda6e2dc1e96ed26ba1a451fe0c4bb2bf6f774fb","tests/oniguruma.rs":"78a54ef464d08fa7192959eb50c3de03df7dae0f9d41831b06ecfa170dfcfd65","tests/oniguruma/.gitattributes":"b8d35d419a619abf4283b4f1e8a3daeaca142c87df6634b4cd706b726d29a88d","tests/oniguruma/README.md":"eae6ac089cd32010ffacb4b2f0f8cbac03ad2623e115386af53bfc93e04d1903","tests/oniguruma/test_utf8.c":"1e4813ac64703cfdbcdca359b82856c5c6778abf977e577992f6b34ab26b92de","tests/oniguruma/test_utf8_ignore.c":"88760e1779017c58dfca5b03f382df7b067dceefcb4b52d81aef36f096b918a0","tests/regex_options.rs":"1744e707e8d76f19b999728c6b7de6e0e531342d1cd708af61ffbe74cef84a3f","tests/replace.rs":"689fef80c2cd243a510be212cb8e6a04a30a0b0fa6f1dd6be63b17a9abb158d8","tests/splitting.rs":"55a60e7953e92cf542fff8016c24607d3da4fdf9cbf68712348cc430b2bc0f3f"},"package":"6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"}
1+
{"files":{".cargo_vcs_info.json":"cf43644f4417a371f3b570fae27b3a6949dc254c597474a10b7ee23839965437","AUTHORS":"d5fca2653c88ad02d197faead77e22b80c70636b5bec6e02f2805f389a21b86d","CHANGELOG.md":"33e288ac35f2f0045f692c87624de90f10166e3bd0b3b311eeb7d28560a67aa1","CONTRIBUTING.md":"a7e0f3d282301aa5f4b546ed7fc5376159569987a002f24bf57082d49746fde6","Cargo.lock":"8846412681720cb85ae6a79ac3eae84ca145c7cb4a809e0bd52a3cbaed31ee31","Cargo.toml":"fe2d3062136b9c1bdacc09aaf8ad2766a4182de39732498de8bbb21c62f4384a","Cargo.toml.orig":"fc005fab26a48ff9c66f508c538a84b05cb5b5aea0968acf97daf9092687599a","LICENSE":"3bc70e239e91272782006c638fc0452a714d384224f11f0923036b7be07cf9b5","PERFORMANCE.md":"9de4fa787572943e7e350a2688002d571e986190e4869d08587048974bc2fcc6","README.md":"5321b581e5d6bea76875bc3ef93a482184fea9616b45f73781f5ec16542bdf9c","benches/bench.rs":"ec5005c0ec5b5155ae334f9204dffac98b583c377773dbe81e460ecf7404c1d0","codecov.yml":"d6ebfcadb4d940a0f86ab1a99928b673195c7d84cecee17a5eefeaf396c8477b","examples/toy.rs":"33c5f572f2afa1e0d359845708bd984bc95e272b4dcac0eb3ce55668b2a9d03b","src/analyze.rs":"0ea9e0b9661cef8c804a750459d6caf196b298dae1267d52661f1894f88c47d6","src/compile.rs":"54afdafd8004bc3cd27074e949fb1ccf0c81af0992f9c140141bea8f182ed42c","src/error.rs":"931e720cd907f7f62d41c10b69174f286c2944bb4230df8c3c1428aa75056260","src/expand.rs":"6eff8afef144363d8ebbb90922448783cf2ebfc71ef716948bd9da54793663af","src/lib.rs":"5fceb05786b2e860ec2141c8e6bfbb85014c97b4f48cc634d0842b81b0dd6477","src/parse.rs":"8991c0f8b311f404cd63bc8f2beb898055f14c2fd899ccfb86055b396a596229","src/replacer.rs":"5bf1c99d598c27248fd6591dab000e649eedc8f51179f904e00b94ac27919dc3","src/vm.rs":"8442aec0c60680576130f0ebbd6da494bba14d1141e7035f66c68f3849933731","tests/captures.rs":"0b561bbec208af0cdea12c8b10e3c72eab80ef2dbf1a9c1007fdffc7401b4434","tests/common/mod.rs":"b8ab2a7a3a25adad8317c8eb1f4566df6a81978c3a7ab49847ec2f838d77c888","tests/finding.rs":"76e60d370ae71585a304018fe0398e5206fe431fe21bbde6347cc2572afff0e5","tests/matching.rs":"3f8d1e0f6567375866b14610eda6e2dc1e96ed26ba1a451fe0c4bb2bf6f774fb","tests/oniguruma.rs":"78a54ef464d08fa7192959eb50c3de03df7dae0f9d41831b06ecfa170dfcfd65","tests/oniguruma/README.md":"eae6ac089cd32010ffacb4b2f0f8cbac03ad2623e115386af53bfc93e04d1903","tests/oniguruma/test_utf8.c":"1e4813ac64703cfdbcdca359b82856c5c6778abf977e577992f6b34ab26b92de","tests/oniguruma/test_utf8_ignore.c":"88760e1779017c58dfca5b03f382df7b067dceefcb4b52d81aef36f096b918a0","tests/regex_options.rs":"1744e707e8d76f19b999728c6b7de6e0e531342d1cd708af61ffbe74cef84a3f","tests/replace.rs":"689fef80c2cd243a510be212cb8e6a04a30a0b0fa6f1dd6be63b17a9abb158d8","tests/splitting.rs":"55a60e7953e92cf542fff8016c24607d3da4fdf9cbf68712348cc430b2bc0f3f"},"package":"6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"}

hermes/vendor/fancy-regex/tests/oniguruma/.gitattributes

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)